为什么 Django 需要进行引用检查以防止 CSRF

信息安全 tls 中间人 csrf django
2021-09-03 19:10:23

今天我了解到 Django 的 CSRF 保护除了检查隐藏的表单字段与 cookie 外,还使用了refer(r)er 标头检查。从下面的文档和问题来看,这似乎很重要。

它只通过 HTTPS 进行检查。我还注意到几乎没有其他网站检查引用者[因为我关闭了所述标题的发送并且大多数表单仍然有效]。

所以我有两个问题:

  1. 如果没有这项检查,攻击将如何进行?https 不能防止中间人攻击吗?
  2. 其他网站如何防范它?Django 不是为 http 项目吗?

我找到的信息:

https://docs.djangoproject.com/en/1.8/ref/csrf/#how-it-works

此外,对于 HTTPS 请求,严格的 referer 检查由 CsrfViewMiddleware 完成。这对于解决在 HTTPS 下使用独立于会话的 nonce 时可能发生的中间人攻击是必要的,因为 HTTP 'Set-Cookie' 标头(不幸地)被正在与HTTPS 下的站点。(对 HTTP 请求不进行引用检查,因为在 HTTP 下引用头的存在不够可靠。)

https://code.djangoproject.com/ticket/16870

不幸的是,这个检查对于 Django 的 CSRF 保护的安全性是绝对必要的。没有它,我们就无法防止对 SSL 站点的中间人攻击。我们决定,对于以不会改善隐私的方式阻止标题的少数用户来说,阻止 MITM 比破坏网站更有价值。

2个回答

首先,感谢您提出有趣的问题。我之前不知道 CSRF 的细节,不得不自己查找你的问题的答案,但我想我现在知道对 Django 行为的正确解释。

Django 开发人员对待 HTTP 和 HTTPS 的方式不同,因为用户对不安全和安全的 Web 服务有不同的期望。更具体地说,如果网页使用传输层安全性,用户希望受到保护免受中间人攻击,这意味着他们相信即使有人直接坐在他们和远程服务器之间并拦截每一个消息,他们无法使用该信息。请注意,这不是普通 HTTP 连接所期望的。

现在考虑以下场景,引用自 Django 开发人员的帖子

  • 用户浏览到http://example.com/
  • MITM 修改返回的页面,因此它具有一个针对https://example.com/detonate-bomb/的 POST 表单。MITM 必须包含一个 CSRF 令牌,但这不是问题,因为他可以发明一个并发送一个 CSRF cookie 来匹配。
  • POST 表单由用户浏览器的 javascript 提交,因此包含 CSRF cookie、匹配的 CSRF 令牌和用户的会话 cookie,因此将被接受。

我自己并没有立即理解这次攻击,所以我将尝试解释细节。首先请注意,我们正在查看一个通过普通连接显示表单但通过 SSL/TLS 提交数据的页面。据我了解,部分问题在于 cookie 和隐藏表单值(又名“CSRF 令牌”)仅相互比较,而不是与存储在服务器端的任何值进行比较。这使得攻击者很容易向他们的受害者提供将被服务器接受的 cookie-token-combination - 请记住,显示表单的页面是不安全的,因此Set-Cookie标题和表单本身的内容可能会被欺骗。一旦提交了操纵的表单(例如,通过注入的 JS),服务器就会看到一个完全有效的请求。

添加严格Referer检查是这个确切问题的答案。检查这些标头,只有来自的请求https://example.com才会在https://example.com. 来自同一域的不安全页面将被视为完全不受信任,这是正确的。

现在回到为什么对普通 HTTP 请求进行不同处理的问题,我们只需要想象一个根本不使用加密的站点。在这种情况下,中间人也可以欺骗Referer与实际表单数据一起发送的标头,因此检查这些标头不会提供任何额外的安全性。换句话说:没有针对中间人的 CSRF 攻击的保护 - 但是,正如我之前提到的,用户并不期望普通 HTTP 站点具有这种安全性。

关于您关于其他 Web 框架如何处理此攻击向量的问题,老实说,我不得不说我不知道​​。

我将简要总结一下我提出这个问题后的发现。

用户对网站的第一次请求不能保证是 https(来自服务器端)。攻击者可能会使用此请求来设置特定的 CSRF cookie。然后,他可以使用它代表用户从您无法控制的 http 域执行跨站点请求。这是推荐人检查所阻止的。

可能会想到的一个解决方案是在启动经过身份验证的会话时重置 CSRF 令牌。然后攻击者只能伪造对匿名服务的请求,这没有什么好处(他可以直接自己做,毕竟是匿名的)。

问题是登录表单本身也容易受到 CSRF 的攻击,尽管需要密码。在这种情况下,攻击者不会接管用户的会话,而是将用户登录到攻击者的会话中。然后,攻击者可能能够看到用户所做或输入的事情。

一些我认为可以关闭它的罕见情况,都假设 HSTS 已打开并且您在登录时更改了 CSRF 令牌:

  • 您有一个执行以下操作之一的登录过程:

    • 涉及两个页面,CSRF令牌在第一个页面之后更改,因此无法自动化(也设置X-Frame-Options)。例如,需要双因素身份验证,或者只是带有手动确定按钮的第二页。
    • 登录页面具有防止虚假请求的验证码。
    • 用户不会被欺骗为我们的特定服务使用错误的帐户(例如,它以一种对用户显而易见但攻击者无法检测到的方式高度个性化)。
  • 您知道第一个请求将通过 https 进行,例如该页面只能通过您的应用程序或软件访问,而不是通过普通浏览器访问。

  • 浏览器实现了一种方法来查看 cookie 是否为 https-only / 在 https 连接上设置(然后攻击者无法通过 http 设置可用的 cookie)。但目前这是不可能的,而且超出了我们的控制范围。

(使 CSRF 令牌以秘密方式依赖于会话,并存储在服务器端,并不能解决此问题。攻击者无法覆盖或生成 CSRF 令牌,但他可以通过打开一个使用他选择的会话形式)。