Flask-WTF 表单保护你免受 CSRF 威胁,你不须要有任何担忧。尽管如此,若是你有不包含表单的视图,那么它们仍须要保护。javascript
例如,由 AJAX 发送的 POST 请求,然而它背后并无表单。在 Flask-WTF 0.9.0 之前的版本你没法得到 CSRF 令牌。这是为何咱们要实现 CSRF。html
①用户正常登陆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()
在 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") }, ... })