Flask CSRF的保护与cookie中的 csrf_token 和表单中的 csrf_token实现

本文详细介绍了在Flask框架中如何实现CSRF保护,包括CSRFProtect的配置与使用,csrf_token的生成与传递,以及如何在前端请求中正确携带csrf_token。同时,提供了在不同场景下实现CSRF保护的具体代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Flask中请求体的请求开启CSRF保护可以按以下配置

from flask_wtf.csrf import CSRFProtect

  app.config.from_object(Config)

  CSRFProtect(app)
#像任何其它的 Flask 扩展一样,你可以惰性加载它:
from flask_wtf.csrf import CsrfProtect

csrf = CsrfProtect()
def create_app():
    app = Flask(__name__)
    csrf.init_app(app)

但CSRFProtect只做验证工作,cookie中的 csrf_token 和表单中的 csrf_token 需要按以下方式实现

根据 csrf_token 校验原理,具体操作步骤有以下几步:

1、后端生成 csrf_token 的值,在前端请求登录或者注册界面的时候将值传给前端,传给前端的方式可能有以下两种:

(1)在模板中的 From 表单中添加隐藏字段

(2)将 csrf_token 使用 cookie 的方式传给前端

2、在前端发起请求时,在表单或者在请求头中带上指定的 csrf_token

3、后端在接受到请求之后,取到前端发送过来的 csrf_token,与第1步生成的 csrf_token 的值进行校验

4、如果校验对 csrf_token 一致,则代表是正常的请求,否则可能是伪造请求,不予通过

生成 csrf_token 的值

# 导入生成 csrf_token 值的函数
from flask_wtf.csrf import generate_csrf
# 调用函数生成 csrf_token
csrf_token = generate_csrf()

将 csrf_token 的值传给前端浏览器         实现思路:可以在请求勾子函数中完成此逻辑

通过装饰器为一个模块添加请求钩子, 对当前模块的请求进行额外的处理. 比如权限验证,请求钩子放在app文件加的 __init__.py  create_app函数中

def create_app(config_name):
    app = Flask(__name__)
    #请求钩子
    @app.after_request
    def after_request(response):
        # 调用函数生成 csrf_token
        csrf_token = generate_csrf()
        # 通过 cookie 将值传给前端
        response.set_cookie("csrf_token", csrf_token)
        return response

在前端请求时带上 csrf_token 值

(1)根据登录和注册的业务逻辑,当前采用的是 ajax 请求

(2)所以在提交登录或者注册请求时,需要在请求头中添加 X-CSRFToken 的键值对

$.ajax({
   url:"/passport/register",
   type: "post",
   headers: {
          "X-CSRFToken": getCookie("csrf_token")
      },
   // 自定义 getCookie 函数来拿到cookie中的 csrf_token 值(可不写)
   function getCookie(name) {
       var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
       return r ? r[1] : undefined;}
   data: JSON.stringify(params),
   contentType: "application/json",
   success: function (resp) {
       if (resp.errno == "0"){
              // 刷新当前界面
       location.reload()
       }else {
           $("#register-password-err").html(resp.errmsg)
           $("#register-password-err").show()
        }
    }
})

如果模板中有表单,不需要做任何事

<form method="post">
    {{ form.csrf_token }}
      或者:
    {{form.hidden_tag()}}
    ...
</form>

但如果模板中没有表单,你仍需要 CSRF 令牌:

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

如果使用 csrf_token() 函数来作为 token 的值, 你需要设置 X-CSRFToken 请求头

路由想取消 csrf_token认证

在不需要csrf_token认证的路由中加一个装饰器    @csrf.exempt 就可以取消csrf_token认证

### CSRF Token 的生成、使用及安全性 #### 1. CSRF Token 的生成 CSRF Token 是一种随机生成的字符串,通常在用户会话初始化时由服务器生成并绑定到用户的会话中。生成方法可以包括使用加密算法结合时间戳、用户标识符(如用户ID)以及其他动态信息来确保其唯一性[^3]。例如,可以使用以下 Python 示例代码生成一个基于 HMAC 的 CSRF Token: ```python import hmac import hashlib import time import base64 def generate_csrf_token(secret_key, user_id): timestamp = str(int(time.time())) token_data = f"{user_id}:{timestamp}" hashed = hmac.new(secret_key.encode(), token_data.encode(), hashlib.sha256) return base64.urlsafe_b64encode(hashed.digest()).decode() ``` 此代码片段通过结合用户ID时间戳生成一个 HMAC 哈希值,并将其编码为 Base64 格式以提高可读性。 #### 2. CSRF Token 的使用 CSRF Token 的主要用途是防止跨站请求伪造攻击。它通过以下方式实现: - **存储**:Token 通常存储在用户的会话中或作为 HTTP-only Cookie 发送到客户端。 - **传输**:在表单提交或 AJAX 请求中,Token 被嵌入到请求体或头部中[^3]。 - **验证**:服务器接收到请求后,将从请求中提取 Token存储在会话中的 Token 进行比较。如果匹配,则认为请求合法;否则拒绝请求。 以下是 HTML 表单中嵌入 CSRF Token 的示例: ```html <form action="/submit" method="POST"> <input type="hidden" name="csrf_token" value="{{ csrf_token }}"> <button type="submit">Submit</button> </form> ``` 在 JavaScript 中通过 AJAX 请求发送 Token 的示例: ```javascript fetch('/submit', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': '{{ csrf_token }}' }, body: JSON.stringify({ data: 'example' }) }); ``` #### 3. CSRF Token 的安全性 为了确保 CSRF Token 的安全性,需要遵循以下原则: - **绑定会话**:Token 必须用户的会话绑定,避免被其他用户冒用。 - **HTTPS 传输**:所有包含 Token 的通信必须通过 HTTPS 加密,防止中间人攻击。 - **有效期管理**:Token 应具有合理的有效期,过期后需重新生成[^3]。 - **二次验证**:对于关键操作,建议结合短信验证码或 TOTP(基于时间的一次性密码)进行二次验证[^3]。 此外,还需要注意 Token 的存储位置。如果存储在 DOM 中,可能会受到 XSS 攻击的影响;因此推荐使用 HTTP-only Cookie 存储 Token。 #### 示例:CSRF Token 的校验逻辑 以下是一个简单的 Flask 后端校验 CSRF Token 的示例: ```python from flask import request, session, abort def validate_csrf_token(): submitted_token = request.form.get('csrf_token') or request.headers.get('X-CSRF-Token') if not submitted_token: abort(403, "Missing CSRF Token") stored_token = session.get('csrf_token') if not stored_token or submitted_token != stored_token: abort(403, "Invalid CSRF Token") ``` ### 总结 CSRF Token 是一种有效的防御机制,用于防止跨站请求伪造攻击。生成时应确保其唯一性不可预测性,使用时需绑定用户会话并通过 HTTPS 传输,同时定期更新以提高安全性[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值