CSRF即跨站请求伪造,攻击者会诱导已登录的用户点击恶意链接,利用用户的登录状态发起非预期的操作,比如修改账号信息、发起转账等,给Web应用带来严重的安全隐患。Flask本身没有内置CSRF防护机制,借助Flask-WTF扩展的CSRFProtect组件可以很方便地实现全局CSRF防御。

环境准备与安装
首先确保已经安装了Flask和Flask-WTF,如果未安装可以通过pip命令安装:
pip install flask flask-wtf
基础配置步骤
1. 设置应用密钥
CSRFProtect需要用到应用密钥来生成和验证CSRF令牌,必须在初始化CSRFProtect之前设置好密钥,密钥需要足够复杂,不要使用简单的字符串。
from flask import Flask app = Flask(__name__) # 设置应用密钥,生产环境建议使用环境变量存储 app.config['SECRET_KEY'] = 'your_complex_secret_key_here'
2. 初始化CSRFProtect
导入CSRFProtect类,将Flask应用实例传入完成初始化,初始化后所有POST、PUT、PATCH、DELETE请求都会自动触发CSRF验证。
from flask_wtf.csrf import CSRFProtect # 初始化CSRF保护组件 csrf = CSRFProtect(app)
3. 表单中添加CSRF令牌
如果使用Flask-WTF的表单类,表单会自动包含CSRF令牌字段,只需要在模板中渲染即可。如果是原生HTML表单,需要手动添加隐藏的CSRF令牌字段。
Flask-WTF表单示例:
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
class TestForm(FlaskForm):
username = StringField('用户名', validators=[DataRequired()])
submit = SubmitField('提交')
模板中渲染表单:
<form method="post">
{{ form.csrf_token }}
<p>{{ form.username.label }} {{ form.username }}</p>
<p>{{ form.submit }}</p>
</form>
原生HTML表单添加令牌示例:
<form method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="text" name="username">
<input type="submit" value="提交">
</form>
常见配置场景
豁免特定接口的CSRF验证
有些接口比如第三方回调接口、开放API不需要CSRF验证,可以通过装饰器豁免:
from flask import request, jsonify
# 豁免该接口的CSRF验证
@csrf.exempt
@app.route('/api/callback', methods=['POST'])
def api_callback():
data = request.json
return jsonify({'status': 'success', 'data': data})
自定义CSRF错误响应
默认情况下CSRF验证失败会返回400错误,我们可以自定义错误响应内容:
from flask import jsonify
@csrf.error_handler
def csrf_error(reason):
return jsonify({'error': 'CSRF验证失败', 'reason': reason}), 400
注意事项
- 应用密钥必须保密,不要提交到公开的代码仓库中,生产环境建议使用环境变量读取密钥。
- CSRFProtect默认只对POST、PUT、PATCH、DELETE方法做验证,GET请求不会触发验证,符合安全规范。
- 如果项目使用了蓝图,初始化CSRFProtect时传入app即可,不需要在蓝图中重复初始化,全局配置会自动生效。
- 前端如果是通过AJAX发送POST请求,需要在请求头中携带CSRF令牌,令牌可以通过<meta>标签存储后读取。
前端AJAX携带令牌示例:
// 从meta标签获取CSRF令牌
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
fetch('/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({username: 'test'})
})
对应的模板中添加meta标签:
<meta name="csrf-token" content="{{ csrf_token() }}">
FlaskCSRF保护Flask_WTFCSRFProtect全局防御配置修改时间:2026-07-22 12:18:26