Django 的 CSRF 是什么原理?

好像是浏览器发出一个 request 的时候,会在 request header 的 cookie 中携带一个 token,然后在 request 的 body 中也携带一个 token。

然后 Django server 提取 request header cookie 中的 token 和 request body 中的 token?然后比较这两个 Token 是否相同?这个相同是指字符串字面量是否相同吗?还是有什么计算规则?

问题是,跨站攻击的时候,把这两个 token 填成一样不就行了?这能防住啥?


对于跨站攻击,cookie 中的 token 和 form 中的 token 都拿不到吗?都拿不到的话,为什么还需要两个 token?


浏览器本身就不允许跨域,为什么 Django 还要搞一个 csrf?

阅读 3.9k
5 个回答

通过浏览器的 F12 调试发现

与 csrf 相关的 token 一共有两个:

  • csrfmiddlewaretoken,这个 token 存在于 request 的 body 中
  • csrftoken,这个 token 存在于 request 的 cookie 中

先详细看看 csrftoken

图片.png

当我们的浏览器第一次访问的这个网站的时候,request 中当然是没有 csrftoken 的。然后 server 给我们一个 response,这个 response 的 header 中有 Set-Cookie,就如下面的截图一样

第二、三、四、五 etc 次访问的时候,request header cookie 中都会带上这个 csrftoken,对应的 response header 中也有 Set-Cookie 这个 csrftoken。

这个 csrftoken 只要不发生『登录』、『登出』等操作,这个 csrftoken 就不会变,意思就是你 不停刷新,不停请求,都是这个 csrftoken,所以 csrftoken 具有不可变性

再来看看 csrfmiddlewaretoken

先明确一点,必须是先有 GET,才能 POST

当然需要 POST 之前,必然是先 GET 获取这个界面

当你 GET 的时候,Django server 会把 csrfmiddlewaretoken 放在 html 中发给你的浏览器

图片.png

然后当你 POST 的时候,浏览器会把之前 GET 的 csrfmiddlewaretoken 带上,一起 POST 给 Django server

图片.png

而这个 csrfmiddlewaretoken 是变化的,你每次 GET 获得的 csrfmiddlewaretoken 都是不一样的

肯定在生成token的时候,服务器端也生成了,最终是跟服务器端进行匹配

客户端的标记通常存储在一个名为csrftokencookie中,而表单中的标记通常存储在隐藏字段中。

当浏览器发出一个请求时,浏览器会在请求头中包含csrftokencookie的值,而表单中的标记通常被包含在请求体中。

可能有时候请求看起来是有两个cookie,即使有两个,也不是这两个值进行比较

CSRF (Cross-Site Request Forgery) 是一种网络攻击,攻击者可以通过某些手段伪造用户的请求,以便在用户不知情的情况下执行一些非法操作。Django 的 CSRF 机制旨在防止这种类型的攻击。

Django 的 CSRF 机制的原理如下:

  1. 当用户第一次访问 Django 网站时,Django 会在服务器端生成一个随机的 CSRF Token,并在响应的 Cookie 中设置一个名为 csrftoken 的 Cookie。这个 Token 是由一个随机数和一个时间戳组成的,有效期默认为 24 小时。
  2. 当用户向服务器发送一个 POST 请求时,Django 会在请求中包含一个名为 csrfmiddlewaretoken 的隐藏字段,这个字段的值就是在第一次访问时生成的 Token。
  3. 服务器收到请求后,会从 Cookie 中读取 csrftoken 的值,并与请求中的 csrfmiddlewaretoken 值进行比较。如果这两个值相同,那么请求就被认为是合法的,否则就会被认为是 CSRF 攻击,服务器会拒绝该请求。

通过这种方式,Django 的 CSRF 机制可以有效地防止 CSRF 攻击。攻击者无法获取到用户的 csrftoken 值,因为它保存在 Cookie 中,并且只能被同一个域名下的页面访问。攻击者也无法伪造一个合法的 csrfmiddlewaretoken 值,因为它是通过服务器生成的随机数和时间戳组成的,攻击者无法预测它的值。

Django的CSRF(Cross-Site Request Forgery)防护机制是一种安全措施,可以防止恶意网站在用户不知情的情况下进行跨站请求伪造攻击。攻击者通过欺骗用户,在用户登录了受信任网站之后,在用户的计算机上植入恶意脚本,通过用户的浏览器向受信任网站发送伪造请求,从而实现攻击目的。

Django的CSRF防护机制基于以下原理:

服务器生成一个随机的token,并将token存储在服务器端和浏览器端的Cookie中。

当用户在浏览器中提交表单数据时,表单数据中包含token。

服务器端对表单数据中的token进行验证,验证通过后才执行对应的操作。

这样做的好处是,恶意网站无法获取到用户的CSRF token,从而无法发送恶意请求。同时,即使攻击者在某些情况下获取了用户的token,由于token是一次性的,攻击者也只能在一个请求中使用,无法进行长期的攻击。

CSRF这个东西,最好是抛开官方说法用自己的理解去做下表述。主要是搞懂CSRF本身这个东西,然后呢,不同的人可能有不同的实现方案。

首先说这个之前呢,必须要说一下CSRF这个东西是防止第三人拿到用户的cookie相关的东西来进行恶意提交,如果用户自己拿着自己的相关cookie之类的数据做模拟请求,不是CSRF的本意。,我感觉你可能会认为这个CSRF是防止包括用户自己重复发起恶意请求的,导致你理解出现问题了,因为我一开始理解这个的时候也是这么想的。

实际上防止恶意请求是另外一个话题了,一般是做提交频率限制,一天数据创建量限制等等,暂且不表。

那么再回头看这个CSRF,通常来说,这个CSRF的生成,是通过当前用户登录的session_id,当前用户浏览的页面URL地址,以及后端生成的一些随机密钥组合之后做hash后得到的一堆字符串。

说完规则之后,然后用户访问当前页面的时候,会注入到当前页面,不管是存在一个JS的变量里也好,还是放到Form本身也好,这个要看最终处理表单的方式。然后不管怎么处理表单,最后都需要把这个CSRF值提交到后端,后端是不存这个CSRF的,然后会根据对应的规则重新做hash然后对比就能知道请求来源是不是合法的页面。

我上面说的是每个页面都可以生成自己的CSRF,这有个好处就是,如果就算第三方拿到了当前用户的这个CSRF,那么也只能操作当前表单相关的接口,没法操作当前用户其他的相关表单。

另外一种可能就是增加一些时间相关的东西,然后根据当前用户session_id以及后端定义的相关密钥加密后返回给用户,当然提交原理还是一样,然后后端可以解谜这个hash值,还可以校验这个CSRF是否过期。

当然最终千言万语汇成一句话,这个跨站攻击防止是防止第三人利用当前用户信息在第三方页面发起恶意请求不是防止用户自己在第三方页面发起恶意请求

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏