不禁用 CSRF 保护的 Rails API 设计 [英] Rails API design without disabling CSRF protection

查看:42
本文介绍了不禁用 CSRF 保护的 Rails API 设计的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

早在 2011 年 2 月,Rails 就改为要求所有非 GET 请求的 CSRF 令牌,包括 API 端点的请求.我理解为什么这是浏览器请求的重要更改的解释,但该博文并未就 API 应如何处理更改提供任何建议.

Back in February 2011, Rails was changed to require the CSRF token for all non-GET requests, even those for an API endpoint. I understand the explanation for why this is an important change for browser requests, but that blog post does not offer any advice for how an API should handle the change.

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

I am not interested in disabling CSRF protection for certain actions.

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

How are APIs supposed to deal with this change? Is the expectation that an API client makes a GET request to the API to get a CSRF token, then includes that token in every request during that session?

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

It appears that the token does not change from one POST to another. Is it safe to assume that the token will not change for the duration of the session?

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

I don't relish the extra error handling when the session expires, but I suppose it is better than having to GET a token before every POST/PUT/DELETE request.

推荐答案

老问题,但安全性足够重要,我觉得它值得一个完整的答案.正如在这个问题中所讨论的,有即使使用 API,仍有一些 CSRF 风险.是的,默认情况下浏览器应该防止这种情况发生,但由于您无法完全控制用户安装的浏览器和插件,因此在您的 API 中防止 CSRF 仍应被视为最佳做法.

Old question but security is important enough that I feel it deserves a complete answer. As discussed in this question there are still some risk of CSRF even with APIs. Yes browsers are supposed to guard against this by default, but as you don't have complete control of the browser and plugins the user has installed, it's should still be considered a best practice to protect against CSRF in your API.

我所看到的方法有时是从 HTML 页面本身解析 CSRF 元标记.我不太喜欢这个,因为它不适合当今许多单页 + API 应用程序的工作方式,我觉得应该在每个请求中发送 CSRF 令牌,无论它是 HTML、JSON 还是 XML.

The way I've seen it done sometimes is to parse the CSRF meta tag from the HTML page itself. I don't really like this though as it doesn't fit well with the way a lot of single page + API apps work today and I feel the CSRF token should be sent in every request regardless of whether it's HTML, JSON or XML.

所以我建议改为通过所有请求的后过滤器将 CSRF 令牌作为 cookie 或标头值传递.API 可以简单地将其作为 Rails 已经检查过的 X-CSRF-Token 的标头值重新提交回来.

So I'd suggest instead passing a CSRF token as a cookie or header value via an after filter for all requests. The API can simply re-submit that back as a header value of X-CSRF-Token which Rails already checks.

这就是我用 AngularJS 做到的:

This is how I did it with 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 自动查找名为 XSRF-TOKEN 的 cookie代码>,但您可以根据自己的目的随意命名.然后,当您提交 POST/PUT/DELETE 时,您应该设置 Rails 自动查找的标头属性 X-CSRF-Token.

AngularJS automatically looks for a cookie named XSRF-TOKEN but feel free to name it anything you want for your purposes. Then when you submit a POST/PUT/DELETE you should to set the header property X-CSRF-Token which Rails automatically looks for.

不幸的是,AngualrJS 已经在 X-XSRF-TOKEN 的标头值中发回了 XSRF-TOKEN cookie.很容易覆盖 Rails 的默认行为以在 ApplicationController 中适应这一点,如下所示:

Unfortunately, AngualrJS already sends back the XSRF-TOKEN cookie in a header value of X-XSRF-TOKEN. It's easy to override Rails' default behaviour to accomodate this in ApplicationController like this:

  protected

  def verified_request?
    super || form_authenticity_token == request.headers['X-XSRF-TOKEN']
  end

对于 Rails 4.2,现在有一个内置的帮助器来验证应该使用的 CSRF.

For Rails 4.2 there is a built in helper now for validating CSRF that should be used.

  protected

  def verified_request?
    super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN'])
  end

希望对您有所帮助.

关于 Rails 拉取请求的讨论中,我提交了它发现通过 API 传递 CSRF 令牌进行登录是一种特别糟糕的做法(例如,有人可以为您的站点创建使用用户凭据而不是令牌的第三方登录).所以洞穴清空者.由您决定您对应用程序的关注程度.在这种情况下,您仍然可以使用上述方法,但仅将 CSRF cookie 发送回已经具有经过身份验证的会话的浏览器,而不是针对每个请求.这将阻止在不使用 CSRF 元标记的情况下提交有效登录.

In a discussion on this for a Rails pull-request I submitted it came out that passing the CSRF token through the API for login is a particularly bad practice (e.g., someone could create third-party login for your site that uses user credentials instead of tokens). So cavet emptor. It's up to you to decide how concerned you are about that for your application. In this case you could still use the above approach but only send back the CSRF cookie to a browser that already has an authenticated session and not for every request. This will prevent submitting a valid login without using the CSRF meta tag.

这篇关于不禁用 CSRF 保护的 Rails API 设计的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆