老问题,但安全性很重要,我觉得它应该得到一个完整的答案。正如在question中讨论的那样,即使使用API,CSRF仍然存在一些风险。是的,浏览器在默认情况下应该防范这种情况,但由于您没有完全控制用户安装的浏览器和插件,所以在您的API中仍应被视为防止CSRF的最佳做法。
我有时看到它的做法有时是从HTML页面本身解析CSRF元标记。我不太喜欢这一点,因为它不适合很多单页+ API应用程序的工作方式,我认为CSRF令牌应该在每个请求中发送,而不管它是HTML,JSON还是XML。
所以我建议通过一个后置过滤器为所有请求传递CSRF令牌作为cookie或标头值。该API可以简单地重新提交,作为Rails已经检查的标题值X-CSRF-Token
。
这是我如何与AngularJS做到了:
# In my ApplicationController
after_filter :set_csrf_cookie
def set_csrf_cookie
if protect_against_forgery?
cookies['XSRF-TOKEN'] = form_authenticity_token
end
end
AngularJS automatically looks for a cookie命名XSRF-TOKEN
但随时将其命名为任何你想要你的目的。然后,当您提交POST/PUT/DELETE时,您应该设置Rails自动查找的标题属性X-CSRF-Token
。
不幸的是,AngualrJS已经以X-XSRF-TOKEN
的标题值发回了XSRF-TOKEN
cookie。人们很容易忽略Rails的默认行为ApplicationController
这样,以适应这一点:
protected
def verified_request?
super || form_authenticity_token == request.headers['X-XSRF-TOKEN']
end
对于Rails的4.2有一个内置的助手,现在用于验证CSRF应使用。
protected
def verified_request?
super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN'])
end
我希望这很有帮助。
编辑:在我提交的discussion on this for a Rails pull-request中,传出CSRF令牌通过API登录是一种特别糟糕的做法(例如,某人可以为您的站点创建使用用户凭证而不是令牌的第三方登录名) 。所以c em不驯。这取决于你决定你的应用程序对你的担心。在这种情况下,您仍然可以使用上述方法,但只能将CSRF Cookie发回给已具有已验证会话的浏览器,而不是针对每个请求。这将阻止提交有效的登录,而不使用CSRF元标记。
我链接的页面不同意:“某些浏览器插件和HTTP重定向的组合可以用来欺骗用户的浏览器进行跨域请求,其中包括攻击者指定的任意HTTP标头,攻击者可以利用它来欺骗ajax和API请求,并绕过内置的CSRF保护并成功攻击应用程序。“ –
“这与API无关,因为它们不在浏览器中运行”:有时,浏览器*是API的客户端 - 即, – antinome
http://stackoverflow.com/questions/9362910/rails -warning -cant-verify-csrf-token-authenticity-for-json-devise-requests/10049965#10049965 – montrealmike