伪造跨站请求伪造 (CSRF) 令牌

Forging a Cross Site Request Forgery (CSRF) token

我查看了 Rails' ActionController::RequestForgeryProtection 模块,但找不到任何与使用机密相关的内容。基本上,它使用安全的 PRNG 作为一次性一密本、xors、计算 Base64 并嵌入到 HTML(表单、标签)中。我同意攻击者不可能猜出 PRNG 生成的内容,但是我可以生成(如果你愿意,也可以伪造)一个类似的令牌,将其嵌入到我的“邪恶”表单中并提交。据了解 Rails 在后端比较(验证)它。但我不能完全理解为什么它是安全的。毕竟,我可以像 Rails 一样生成自己的令牌。有人可以阐明安全性是如何实现的吗?

你可能会误解这是为了防止什么,所以让我们先弄清楚什么是 CSRF,什么不是。很抱歉,如果这不是混淆的地方,可能对其他人仍然有帮助,我们稍后会进入正题。

假设您有一个应用程序,允许您通过 POST 请求转账(做一些“改变状态”的事情),并使用基于 cookie 的会话。 (请注意,这不是 csrf 唯一可能的情况,而是迄今为止最常见的情况。)此应用程序接收请求并执行操作。作为攻击者,我可以在不同的域上设置另一个应用程序,并让用户访问我的恶意应用程序。它甚至不必看起来与真实的相似,它可以完全不同,只要让用户访问我的流氓域就足够了。然后,我作为攻击者可以向受害者应用程序的域发送一个 post,精确到 url,并带有所有必要的参数,以便转移资金(将执行操作)。受害用户甚至不需要知道这是否发生在来自 javascript 的 xhr 中——或者我可以正确地 post 一个表单,用户被重定向,但伤害已经造成。

这受到一些因素的影响,但关键是同源策略不会阻止跨源请求,只有响应对其他域不可用 - 但在这种情况下,当服务器状态受害应用程序的更改(如转账),攻击者可能不太关心响应本身。所有这一切都需要受害者用户访问攻击者的页面,同时仍然登录到受害者应用程序。无论请求从哪个页面发送,Cookie 都将随请求一起发送,唯一重要的是目标域(好吧,除非为 cookie 设置了 samesite,但那是另一回事)。

好的,那么 Rails(以及类似的同步器令牌解决方案)如何防止这种情况发生?如果您查看 source 中的第 318 和 322 行,将从用户收到的令牌与已存储在会话中的令牌进行比较。当用户登录时,会为该特定用户、该特定会话生成并存储一个随机令牌。更改状态的后续请求(除 GET 之外的所有请求)检查从客户端接收到的令牌是否与存储在会话中的令牌相同。如果您(或攻击者)生成并发送一个新的,那将是不同的,请求将无法通过验证。他们自己网站上的攻击者无法猜测要发送的正确令牌,因此上述攻击变得不可能。不同来源的攻击者也无法读取用户的令牌,因为同源策略阻止了这一点(攻击者可以向受害应用程序发送 GET 请求,但无法读取响应)。

所以澄清一下,CSRF 不是防止参数篡改的保护措施,这可能会让您感到困惑。在你自己的请求中,如果你知道令牌,你可以以任何方式更改请求,发送任何参数,CSRF 令牌不能防止这种情况。它反对上述攻击。

请注意,上面的描述只是触及表面,CSRF 保护有很多深度,Rails 也做的更多一些,其他一些框架做的更多以防止更少可能的攻击。