csrf原理及flask的处理方法

csrf原理及flask的处理方法

为何须要CSRF?

Flask-WTF 表单保护你免受 CSRF 威胁,你不须要有任何担忧。尽管如此,若是你有不包含表单的视图,那么它们仍须要保护。javascript

例如,由 AJAX 发送的 POST 请求,然而它背后并无表单。在 Flask-WTF 0.9.0 之前的版本你没法得到 CSRF 令牌。这是为何咱们要实现 CSRF。html

CSRF攻击的原理:

        ①用户正常登陆A银行网站,前端

        ②A网站返回cookie信息给用户,浏览器保存cookie信息java

        ③在A网站没有退出登陆的状况下(或者说cookie信息没过时), 登陆了恶意网站Bajax

        ④恶意网站B,提早准备好转帐表单或者其它请求 ,将其隐藏. 把提交到A网站的按钮设置为一个"领取优惠券"的图片连接.用户 点击连接flask

        ⑤在用户主观未知的状况下,访问A网站,此时浏览器会自动携带cookie信息后端

        ⑥A网站识别到cookie信息,默认为是用户本人作出的请求,根据请求作出相应的操做.浏览器

        ⑦用户收到损失.cookie

具体操做步骤:

根据 csrf_token 校验原理,具体操做步骤有如下几步:
1.后端生成 csrf_token 的值,在前端请求登陆或者注册界面的时候将值传给前端,传给前端的方式可能有如下两种:
在模板中的 From 表单中添加隐藏字段
将 csrf_token 使用 cookie 的方式传给前端
2.在前端发起请求时,在表单或者在请求头中带上指定的 csrf_token
3.后端在接受到请求以后,取到前端发送过来的 csrf_token,与第1步生成的 csrf_token 的值进行校验
4.若是校验对 csrf_token 一致,则表明是正常的请求,不然多是伪造请求,不予经过app

而在 Flask 中,CSRFProtect 这个类专门只对指定 app 进行 csrf_token 校验操做,因此开发者须要作如下几件事情:
生成 csrf_token 的值
将 csrf_token 的值传给前端浏览器
在前端请求时带上 csrf_token 值

而后实现

处理方法:

后端书写:

为了可以让全部的视图函数受到 CSRF 保护,须要开启 CsrfProtect 模块:

from flask_wtf.csrf import CsrfProtect
CsrfProtect(app)

像任何其它的 Flask 扩展同样,你能够惰性加载它:

复制代码
from flask_wtf.csrf import CsrfProtect
csrf = CsrfProtect()
 
def create_app():
  app = Flask(__name__)
  csrf.init_app(app)
复制代码

 

Note
须要为 CSRF 保护设置一个秘钥。一般下,同 Flask 应用的 SECRET_KEY 是同样的。

在表单添加保护操做:

若是模板中存在表单,不须要作任何事情。与以前同样:

<form method="post" action="/">
  {{ form.csrf_token }}
</form>

可是若是模板中没有表单,就须要一个 CSRF 令牌:

<form method="post" action="/">
  <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
</form>

自定义错误相应和关闭保护:

不管什么时候未经过 CSRF 验证,都会返回 400 响应。能够自定义这个错误响应:

@csrf.error_handler
def csrf_error(reason):
  return render_template('csrf_error.html', reason=reason), 400

建议对全部视图启用 CSRF 保护。也提供了某些视图函数不须要保护的装饰器:

@csrf.exempt
@app.route('/foo', methods=('GET', 'POST'))
def my_handler():
  # ...
  return 'ok'

默认状况下也能够在全部的视图中禁用 CSRF 保护,经过设置 WTF_CSRF_CHECK_DEFAULT 为 False,仅仅当须要的时候选择调用 csrf.protect()。这也可以在检查 CSRF 令牌前作一些预先处理:

@app.before_request
def check_csrf():
  if not is_oauth(request):
    csrf.protect()

Ajax提交数据:

在 meta 标签中渲染 CSRF 令牌:

<meta name="csrf-token" content="{{ csrf_token() }}">

在 script 标签中渲染一样可行:

<script type="text/javascript">
  var csrftoken = "{{ csrf_token() }}"
</script>

下面的例子采用了在 meta标签渲染的方式, 在 script 中渲染会更简单,无须担忧没有相应的例子。

不管什么时候,发送 AJAX POST 请求,为其添加 X-CSRFToken 头:

复制代码
var csrftoken = $(‘meta[name=csrf-token]').attr(‘content')
 
KaTeX parse error: Expected '}', got 'EOF' at end of input: …|OPTIONS|TRACE)/i.test(settings.type) && !this.crossDomain) {
xhr.setRequestHeader(“X-CSRFToken”, csrftoken)
}
}
})
复制代码

或者这么写ajax:
在提交请求时,须要在请求头中添加 X-CSRFToken 的键值对:

复制代码
$.ajax({
  ...
  headers: {
    "X-CSRFToken": getCookie("csrf_token")
  },
  ...
})
相关文章
相关标签/搜索