Flask API后端+HTML+jQuery前端的CSRF防护最佳实现方式是什么?
不用改前端成Jinja模板完全没问题!我之前也遇到过类似的场景,给你一套轻量的实现方案,不用依赖Flask-WTF,纯手动搞定CSRF防护:
1. 先配置Flask的核心密钥
首先确保你的Flask应用已经设置了SECRET_KEY,因为我们要借助加密的session来存储CSRF token,这是基础要求:
from flask import Flask, session app = Flask(__name__) # 建议从环境变量读取,别硬编码在代码里 app.config['SECRET_KEY'] = 'your-secure-secret-key-here'
2. 写一个接口给前端获取CSRF Token
我们需要生成安全的随机token并存在session中,同时提供一个GET接口让前端拿到这个token:
import secrets from flask import jsonify @app.route('/api/csrf-token', methods=['GET']) def get_csrf_token(): # 如果session里没有token,就生成一个16字节的随机字符串 if 'csrf_token' not in session: session['csrf_token'] = secrets.token_hex(16) return jsonify({'csrf_token': session['csrf_token']})
用secrets模块生成的随机字符串比random更安全,适合做安全凭证。
3. 前端用jQuery自动携带Token
页面加载时先获取token,然后通过全局AJAX配置,让所有修改型请求自动带上token到请求头:
// 页面加载完成后获取CSRF token let csrfToken; $(document).ready(function() { $.get('/api/csrf-token') .done(function(res) { csrfToken = res.csrf_token; }); }); // 全局配置AJAX,给非GET请求自动添加CSRF请求头 $.ajaxSetup({ beforeSend: function(xhr) { if (csrfToken && this.method !== 'GET') { xhr.setRequestHeader('X-CSRFToken', csrfToken); } } });
这样不管是POST/PUT/DELETE的AJAX请求,都会自动带上X-CSRFToken头,不用每个请求手动写。
4. 后端全局验证Token
用Flask的before_request钩子,对所有非幂等请求(也就是会修改数据的请求)做Token验证:
from flask import request, jsonify @app.before_request def validate_csrf_token(): # GET/HEAD/OPTIONS这类只读请求不需要CSRF防护 safe_methods = ['GET', 'HEAD', 'OPTIONS'] if request.method not in safe_methods: # 从请求头拿到前端传的token received_token = request.headers.get('X-CSRFToken') # 和session里存储的token比对 if not received_token or received_token != session.get('csrf_token'): return jsonify({'error': 'Invalid or missing CSRF token'}), 403
如果token不匹配或者缺失,直接返回403禁止访问,拦截恶意请求。
额外小贴士
- 如果是跨域场景,需要配合Flask-CORS,设置
supports_credentials=True,同时前端AJAX要加xhrFields: {withCredentials: true},这样session才能正常传递。 - 用户登录成功后,建议重新生成CSRF token(删除旧的再生成新的),避免token复用带来的风险。
- 如果有非AJAX的表单提交,可以把token放在隐藏的
<input>里,后端从request.form.get('csrf_token')获取验证,原理和请求头一致。
内容的提问来源于stack exchange,提问作者Kari Fox
相关产品推荐
相关产品推荐

