Python中的CSRF攻击与Referer验证

2023-04-17 00:00:00 python 验证 攻击

CSRF攻击(Cross-Site Request Forgery)也称为“跨站请求伪造”,是一种网络攻击方式,利用用户在已登录的情况下,通过伪造用户请求的方式向服务器发送请求,从而执行恶意操作。

为了防止CSRF攻击,常用的措施是在每次请求中加上一个Token,在后端进行验证。具体步骤如下:

  1. 将Token添加到表单中

在所有需要进行身份验证的表单中,需要添加一个隐藏的input框,其名称为"_csrf_token",值就是生成的Token。可以使用UUID等算法生成随机数作为Token。

<form method="POST">
  <!-- 其他表单内容 -->
  <input type="hidden" name="_csrf_token" value="生成的Token">
  <button type="submit">提交</button>
</form>
  1. 后端进行验证

当服务器收到表单提交的请求时,需要在后端进行验证。首先,需要从请求中获取Token,这里使用Python的Flask框架作为示例。

from flask import Flask, request, abort
from uuid import uuid4

app = Flask(__name__)
app.secret_key = 'a secret key'
app.config['WTF_CSRF_SECRET_KEY'] = 'a secret key'

@app.before_request
def csrf_protect():
  if request.method == 'POST':
    csrf_token = request.form.get('_csrf_token')
    if csrf_token is None or csrf_token != session.pop('_csrf_token', None):
      abort(403)

@app.route('/')
def index():
  return 'Hello, world!'

if __name__ == '__main__':
  app.run()

在Flask框架中,可以使用before_request修饰器来注册一个预处理函数,该函数会在处理每个请求之前被调用。在这个函数中,我们判断请求的方法是否是POST,如果是,就获取请求表单中的Token,然后与服务器存储的Session中的Token对比。如果Token不匹配,就返回403错误。

在Flask框架中,Session中的Token可以通过访问session['_csrf_token']来获取,session.pop('_csrf_token', None)则是从Session中弹出Token元素。注意,后一个参数是默认值,如果Session中不存在'_csrf_token'键,就返回None。

  1. 给Session添加Token

在每个请求中,服务器都需要在Session中添加一个Token,以便在后面的请求中进行验证。Token的生成方法已经在上面介绍过了,这里只需要在每个请求处理的函数中添加一行代码就行了。

@app.route('/login', methods=['GET', 'POST'])
def login():
  if request.method == 'POST':
    session['_csrf_token'] = str(uuid4())
    return redirect('/')
  return render_template('login.html')

在这个示例中,当用户通过POST方法提交表单时,服务器会生成一个Token,并将其存储在Session中。最后,重定向到首页。

Referer验证

Referer指的是请求的来源地址,在HTTP请求中由请求头信息中的'Referer'字段指明。通过验证Referer可以防止一些攻击,如阻止第三方网站通过iframe等方式嵌入我们的网站页面中,防止自己的服务器成为D盾等。

假设我们的网站只允许在pidancode.com域名下提交请求,那么可以在Flask框架中的每个请求处理函数中添加以下代码:

from flask import request

@app.before_request
def check_referer():
  # 如果请求的来源地址不是pidancode.com,则返回403错误
  if not request.referrer.startswith('http://pidancode.com/'):
    abort(403)

在这个代码中,可以使用before_request修饰器来注册一个预处理函数。该函数会在处理每个请求之前被调用。在这个函数中,我们判断请求的来源地址是否是以'http://pidancode.com/'开头,如果不是,就返回403错误。

需要注意的是,Referrer信息是可以伪造的,所以这种方式并不能完全防止攻击。

相关文章