在 Rails 应用服务 Web 和 API 中正确使用 protect_from_forgery

Correct use of protect_from_forgery in Rails app serving Web and API

我正在开发一个 Rails 4 应用程序,它通过 API 为移动应用程序提供服务,并有一个网络 UI 供管理员管理该应用程序。用户还会看到几个网页(成功的电子邮件确认和重设密码)。

我创建了两组控制器:一组继承自APIController,另一组继承自AdminController。这两个都继承自 ApplicationController。其余负责面向用户的网页的控制器也继承自 ApplicationController。

鉴于此方案,我不确定如何使用 protect_from_forgery 正确实施 CSRF 保护。我目前有以下内容:

class ApplicationController < ActionController::Base
  # ...
end

module API
  class APIController < ApplicationController
    protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }
    # ...
  end
end

module Admin
  class AdminController < ApplicationController
    protect_from_forgery with: :exception
    # ...
  end
end

class UsersController < ApplicationController
  protect_from_forgery with: :exception
  # ...
end

所以我的问题是:这是正确的吗?有什么办法可以改善吗? API 控制器中的检查是否毫无意义,因为所有 API 请求无论如何都将只有 JSON?

Brakeman 抱怨 ApplicationController 中没有 protect_from_forgery 调用,但也许它没有看到子类中的调用。

提前致谢!

您可以看到 here, on their (brakeman) Github page 它仅检查 ApplicationController

上是否存在

您的管理员和用户控制器与 protect_from_forgery with: :exception

没问题

Rails 4 上 protect_from_forgery 的默认行为是 :null_session,如果需要,您可以删除选项 with:

关于改进,我会实现一种方法来在用户中保存令牌并匹配每个请求,这样请求 API 的用户就必须在每个请求中发送他的令牌。这样做可以避免获取 CSRF 令牌然后使用该令牌发送请求的必要性。例如,对于移动用户,这是一个额外的请求,您只需保存正确的令牌即可解决。如果有人得到这个令牌,它可以作为用户传递并更改数据。但是您可以寻找更多方法来提高安全性。

如果您将令牌保存在会话或 cookie 中,则可能会发生 CSRF,如果您选择那样保存,则必须独立处理。

如果你打算在手机上使用API,将token(我前面说的策略)保存在手机(内存或本地数据库)上,这样会更安全。