我正在使用 Sinatra 并使用 sinatra-authentication gem 进行身份验证,以及自定义表单(如联系表单)。
为了帮助解决 CSRF 问题,我设计了一个小解决方案,可以使用来自 sinatra-authentication 的预定义路由以及自定义路由。
before do
if request.post?
if session[:csrf] != params[:csrf]
halt 503, erb('<h1>500: oops</h1>')
end
end
time = Time.now.to_s
@key = Digest::SHA1.hexdigest(time)
session[:csrf] = @key
end
因此,在每个页面请求上,它都会设置一个会话,该会话是当前时间的哈希值。这个散列也使用隐藏元素设置到每个表单<input type="hidden" name="csrf" value="<%= @key %>" />
。提交表单时,它会在原始表单中before
检查存储在会话中的项目,并将提交的项目作为隐藏值。简单的!
但是...这在 localhost 上运行良好,在我的 herokuapp.com 域上运行良好,在我的www
域上运行良好(这是 herokuapp.com 域的 cname),但它不适用于non-www
域(这是 A 记录对于 Heroku 的 IP 集)。
我能看到的唯一区别是non-www
DNS 中具有 A 记录的域似乎正在设置清漆标头,因此必须在某处通过清漆,但由于会话在 rack.session 内,我想知道清漆是否正在过滤这个出去。
那么最终,为什么要if session[:csrf] != params[:csrf]
返回true
?