在阅读了CSRF保护在Rails中的工作原理后,我尝试通过执行以下操作来触发CSRF保护:
注意:我们正在使用基于cookie的会话。
访问登录页面。检查meta => abc123中的CSRF令牌
打开第二个浏览器选项卡,然后访问相同的登录页面。 meta中的CSRF令牌不同=> def456
返回第一个标签。
提交登录凭据。
我期望这会失败,因为第二个选项卡生成了一个新的不同的CSRF令牌。提交登录表单时,提交给服务器的令牌不应该是旧的,陈旧的令牌吗?
但是,这确实有效:
访问登录页面。检查meta => abc123中的CSRF令牌
打开第二个浏览器选项卡,然后访问相同的登录页面。 meta中的CSRF令牌不同=> def456
返回第一个标签。
提交登录凭据。
注销(清除会话)
转到第二个选项卡,然后提交登录。
在这种情况下,我得到一个InvalidAuthenticityToken异常,如预期的那样。为什么?
最佳答案
资料来源:https://medium.com/rubyinside/a-deep-dive-into-csrf-protection-in-rails-19fa0a42c0ef
为什么第二个选项卡中的请求不会失败meta
标记中的CSRF令牌实际上是两个字符串的串联:每个请求生成一个“一次性填充”,以及与一次性填充进行异或的“真实” CSRF秘密。在下图中,请参阅如何将一次性密码垫添加到被屏蔽令牌中的XORed字符串之前,该字符串存储在meta
标记中:
Rails将CSRF机密存储在会话cookie中,而无需进行XORing。浏览器应使用Javascript从meta
标记中读取被屏蔽的令牌,并将其传递到X-CSRF-TOKEN
标头中。
当Rails验证请求时,它:
拆分在X-CSRF-TOKEN
头中传递的值以检索一次性填充和XORed字符串。
将它们异或以获取真正的秘密。
将此与cookie中的秘密进行比较。
这就是为什么您在meta
标记中看到更改令牌的原因-一次性垫不同。如果您验证了令牌,则会在两个令牌中找到相同的秘密。
注意:这项一次性垫业务似乎不必要。任何人只要拥有被屏蔽的令牌,都可以检索真实机密。令人惊讶的是,XORing的目的是在每个请求上更改CSRF令牌,以使攻击者无法使用定时攻击来识别机密。请参见this paper on the BREACH SSL attack。
为什么请求在注销时失败
如@max's comment中所述,注销将删除会话cookie。下一个请求生成一个新的CSRF机密,该机密不再与旧的掩码令牌匹配。
关于ruby-on-rails - 为什么Rails中的CSRF token 不会阻止多个选项卡正常工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47723379/