首页 文章

Rails API设计,不会禁用CSRF保护

提问于
浏览
42

早在2011年2月,Rails就更改为require the CSRF token for all non-GET请求,甚至是API endpoints 的请求 . 我理解为什么这是浏览器请求的重要更改的解释,但该博客文章没有提供有关API应如何处理更改的任何建议 .

我对某些操作禁用CSRF保护不感兴趣 .

API如何应对这种变化?期望API客户端向API发出GET请求以获取CSRF令牌,然后在该会话期间的每个请求中包含该令牌吗?

似乎令牌不会从一个POST更改为另一个POST . 假设令牌在会话期间不会改变是否安全?

我不喜欢会话到期时的额外错误处理,但我认为它比在每个POST / PUT / DELETE请求之前获取令牌更好 .

2 回答

  • 45

    老问题,但安全性很重要,我觉得它应该得到一个完整的答案 . 正如本文所讨论的那样,即使使用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自动查找的 Headers 属性 X-CSRF-Token .

    不幸的是,AngualrJS已经在 X-XSRF-TOKEN 的标头值中发回 XSRF-TOKEN cookie . 它's easy to override 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元标记的情况下提交有效登录 .

  • 5

    Rails使用'默认安全'约定 . 跨站点或跨会话请求伪造要求用户拥有浏览器和另一个受信任的网站 . 这与API无关,因为它们不在浏览器中运行,也不维护任何会话 . 因此,您应该禁用API的CSRF .

    当然,您应该通过要求HTTP身份验证或自定义实现的API令牌或OAuth解决方案来保护您的API .

相关问题