在我的一个控制器中,我编写了以下代码来保护某些页面不受CSRF的攻击。
protect_from_forgery :only => [:foo, :bar]
当我加载对应于foo
和bar
的URL时,我查看HTML,我没有看到任何隐藏的输入字段或包含任何安全令牌的元标记,如这里所述。
然而,在测试期间,我确实观察到CSRF
对这些页面无效,尽管它对同一应用程序中未受保护的其他页面有效。
那么,Rails 4
在哪里存储用于验证请求来自原始页面的安全令牌呢?
请注意,我已经通读了Ruby On Rails安全指南,从protect_from_forgery
部分来看,它说
这将自动在所有表单和Ajax中包含安全令牌由Rails生成的请求。如果安全令牌与什么不匹配 会话将被重置。
问题是这个安全令牌似乎在启用了CSRF保护的页面上的表单中丢失了,尽管CSRF确实对它们无效。
注意,这段代码来自一个类项目,其中一个目标是执行clickjacking攻击来绕过CSRF项目。我在这里问的问题是与赋值的目的无关。
我只是好奇Rails到底是如何实现CSRF的。
在直接做了rails server
之后,我找不到安全令牌的相关URL是http://localhost:3000/protected_transfer
。
CSRF令牌存储在用户的会话中(在Rails中默认存储在cookie中;它通过csrf_meta_tags
助手方法作为<meta>
标签(供Javascript库使用)以及在页面中由form_tag
或form_for
生成的任何表单中作为隐藏字段写入页面。
查看这个项目,CSRF令牌没有出现的原因是HTML是用文字<form>
标记编写的,而不是用form_for
helper编写的,后者将包含CSRF令牌。此外,csrf_meta_tags
helper不存在于布局中,这就是为什么meta标签没有被写入的原因。
这个表单是硬编码到<form action="post_transfer" method="post">
的,不应该被CSRF保护,所以这个表单应该是CSRF-able的,即使视图被标记为protect_from_forgery
。protected_post_transfer
方法甚至不可能接受合法的请求,因为真实性令牌永远不会发送。
我怀疑指导员错过了这一点,因为测试将合法地使用表单(击中未验证的端点,并让它成功),然后指示学生尝试对受保护的端点进行CSRF(无论如何都不会通过检查),因此您最终测试了两种不同的东西,它们出于错误的原因产生了正确的结果。