CSRF 令牌未绑定到 Spring 应用程序中的会话

信息安全 csrf 弹簧框架
2021-09-07 18:52:11

我们正在使用 Spring Security 开发一个 Spring 应用程序。在做了一些渗透测试后,其中一个测试结果是一个漏洞:

跨站点请求伪造令牌未绑定到用户上下文。

我们开始在私人浏览等中使用令牌,我们确信会话都是独立的,我们注意到应用程序从这些会话中的任何一个会话中接受令牌,即我们可以在一个会话中获取令牌并且简单地操纵另一个 sesson 的隐藏输入来使用这个令牌,当我们提交表单时,没有来自 Spring 的任何抱怨。

在我看来,这似乎是一个安全漏洞,因为(例如)在发现用户 X 正在使用我们的应用程序后,运行邪恶网站 example.com 的人也可以使用我们的应用程序并从他/她的会话中获取他们的 CSRF-Token,在邪恶网站 example.com 上设置一个表单,将其发布到我们的应用程序,并引诱用户 X 使用此表单。

我很难相信我在 Spring/Spring Security 中偶然发现了一些未知的安全漏洞,那么我错过了什么?我误解了 CSRF 吗?我的攻击向量不是现实的攻击向量吗?

在安全配置方面,我们主要使用Spring Security 文档的这一部分来配置 CSRF。

2个回答

所以,我们已经解决了。Spring Security 将 CSRF-Token 设置为 cookie,恶意站点 example.com 无法访问该 cookie,因为站点无法访问非来自其域的 cookie。提交表单后,有一个隐藏的输入字段,其中包含令牌并且也被提交。Spring 将 cookie 中的令牌与提交的隐藏输入中的令牌进行比较。如果它们匹配,则一切正常,否则返回 403。由于恶意站点 example.com 无法访问 cookie 中的令牌,因此从恶意站点 example.com 提交的表单在隐藏输入中无法拥有正确的 CSRF 令牌(我认为 DNS 欺骗可以让他们访问cookie,但是我们有一个中间人攻击以及 CSRF)

上面测试的问题是,我们同时更改了两个令牌:隐藏输入中的一个以及 cookie 中的一个,如上所述,攻击者无法做到这一点,因此我们的攻击向量确实不切实际.

另外,也正因如此,Spring Security 不需要显式地将 cookie 中的 token 绑定到 session,因为它知道只有我们的域,也就是我们的 App,才能更改 token(其实我觉得有一个“session”的概念cookie”,但这里没有出现),这意味着只要您将 cookie 和隐藏输入中的令牌更改为有效的 UUID,令牌将在服务器端匹配并且 Spring Security 获胜不在乎。我们甚至将 UUID 用于不是由 Spring Security 生成的令牌,这意味着 Spring Security 没有将它们包含在它们的tokenRepository而 Spring Security 仍然不在乎。起初这让我们有点吃惊,但我想既然 cookie 中的令牌确实无法被攻击者访问,Spring Security 只关心它们是否匹配。

我通常可以与 CSRF 交谈,但不能与 Spring 框架(我没有使用过)交谈。由于我无法用 Spring 本身验证您的声明,因此我将按面值接受您的声明。即:

  1. 您可以通过使用您选择的任何会话进行有效调用来获取 CSRF 令牌
  2. 如果您强制任何其他用户使用您的 CSRF 令牌发出请求,Spring 将接受它作为有效令牌

假设您的发现是准确的(我也不怀疑您,我只是无法自己验证),这些是我的直接想法:

  1. 不应允许 CSRF 令牌像这样跨会话。
  2. 我当然会认为这是一个安全漏洞。
  3. 需要有关 Spring 如何验证 CSRF 令牌的其他详细信息来确定此处是否存在实际的攻击向量。

详细地说,CSRF 令牌绝对不能跨会话。每个 CSRF 令牌都应该与生成它的会话相关联,并且它不应该是任何其他会话的有效令牌。正如您所指出的,允许令牌跨会话使攻击者可以事先生成有效令牌。这绝对是个问题。但是,有一些情况可以减轻这里的潜在威胁:

不仅仅是令牌验证

令牌只是防御 CSRF 攻击的一种方式。就个人而言,我发现它们是最直接和最可靠的方法。然而,它们并不是唯一的方法。另一种选择是检查 REFERRER 和 ORIGIN 标头. 如果 Spring 也在检查 REFERRER 和 ORIGIN 标头,那么他们的 CSRF 令牌中的这个弱点不太可能被利用。您所做的测试(通过浏览器工具手动更改 CSRF 令牌)仍会为您留下正确的 REFERRER 和 ORIGIN 标头,这意味着您将通过两个 CSRF 检查。但是,攻击者不可能重现这一点。它对您有用,因为您在实际的应用程序页面上并直接编辑了应用程序页面。攻击者将从完全不同的地方进行 CSRF 攻击,并且不能强制使用 REFERRER 和 ORIGIN 标头。因此,如果 Spring检查 REFERRER 和 ORIGIN 标头,那么您就可以了。

Spring 两者都做吗?我不知道。为什么Spring会两者兼而有之?我不确定,虽然它符合“纵深防御”的概念,所以做这两个测试也不会太疯狂。如果两者兼而有之,那么很明显,即使 CSRF 令牌中的一个很大的弱点也无关紧要。但是,如果它在某些情况下同时执行并忽略其中之一,那么如果您可以使其忽略标头检查并欺骗 CSRF 令牌,则可能存在攻击向量。

CSRF 令牌过期

也可能存在令牌过期,这将使其难以将其转变为可利用的攻击媒介。事实上,它几乎可以肯定有一个令牌到期。作为攻击者,您可以生成一个有效的 CSRF 令牌,但如果它的有效期很短,那么您需要快速将其放在目标面前。假设您构建了一个 CSRF 攻击向量,当管理员查看您生成的恶意页面时,该攻击向量有效地将您的用户帐户提升为管理员。如果您可以在令牌过期之前诱骗管理员查看您的攻击页面,这只会对您有任何好处。根据您的交付方式和令牌到期的长度,这可能非常困难。

总结一下:这是 CSRF 的规范吗?不,事实上它有潜在的危险。可以利用吗?这更难回答。一如既往,魔鬼在细节中。是否值得深入研究?我会这么说。