早在2011年2月,Rails就更改为require the CSRF token for all non-GET个请求,甚至是API端点的请求。我理解为什么这是浏览器请求的重要更改的解释,但该博客文章没有提供有关API应如何处理更改的任何建议。
我对某些操作禁用CSRF保护不感兴趣。
API应该如何应对这种变化?期望API客户端向API发出GET请求以获取CSRF令牌,然后在该会话期间的每个请求中包含该令牌吗?
看起来令牌不会从一个POST更改为另一个。假设令牌在会话期间不会改变是否安全?
我不喜欢会话到期时的额外错误处理,但我认为这比在每个POST / PUT / DELETE请求之前获取令牌更好。
答案 0 :(得分:47)
旧问题,但安全性非常重要,我认为它应该得到完整答案。正如本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已经在XSRF-TOKEN
的标头值中发送回X-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进行登录是一种特别糟糕的做法(例如,有人可以为您的站点创建使用用户凭据的第三方登录令牌)。如此幽默的经纪人。由您来决定您对应用程序的关注程度。在这种情况下,您仍然可以使用上述方法,但只将CSRF cookie发送回已经具有经过身份验证的会话而不是每个请求的浏览器。这将阻止在不使用CSRF元标记的情况下提交有效登录。
答案 1 :(得分:5)
Rails使用'默认安全'约定。跨站点或跨会话请求伪造要求用户拥有浏览器和另一个受信任的网站。这与API无关,因为它们不在浏览器中运行,也不维护任何会话。因此,您应该禁用API的CSRF。
当然,您应通过要求HTTP身份验证或自定义实施的API令牌或OAuth解决方案来保护您的API。