Rails Set-Cookie on json API 响应

Posted

技术标签:

【中文标题】Rails Set-Cookie on json API 响应【英文标题】:Rails Set-Cookie on json API response 【发布时间】:2015-11-28 00:40:00 【问题描述】:

基于简单令牌的 Rails 身份验证。 客户端服务器向 API 服务器发出请求。 API 服务器返回成功状态、json 编码的正文并最好设置一个 cookie。

# response from API  
render json: user: "user", token: "token_string", status: :created

此响应如何也设置 cookie? 我试图将, set_cookie: token 附加到渲染语句。我也有skip_before_filter :verify_authenticity_token, only: :create

最终目标是将令牌存储在浏览器 cookie 中。我不想为令牌使用 html5 存储。

【问题讨论】:

在这种情况下,客户端应用程序应该设置 cookie,而不是 rails。 客户端应用程序接收 json 正文然后设置 cookie?有道理,但那是 API 的标准吗?指望客户端(可以是第 3 方)正确处理令牌? 是的,当涉及到令牌身份验证时,它就是这样工作的。在服务器上,您只想检查每个请求是否具有令牌,并且可能具有令牌何时/是否过期的规则。 @Nathan 不正确。当您使用安全的 httpOnly cookie 作为 SPA 的 API 的 CSRF/XSS 保护的一部分时,从外观上看,这是 OP 试图做的事情,您不希望客户端能够访问曲奇饼。如果他们做了任何 XSS 脚本也将获得访问权限,并且保护将为 0。这里的安全性基于服务器和浏览器具有客户端代码无法访问的合同。阅读 OWASP 指南了解更多信息:owasp.org/index.php/… 【参考方案1】:

这是我的跨域 SPA/API 设置:

我的控制器中有这个,使用 Knock gem,操作:

class AccountTokenController < Knock::AuthTokenController
  def  create
    response.set_cookie(
      :jwt,
      
        value: auth_token.token,
        expires: 30.minutes.from_now,
        path: '/api',
        secure: Rails.env.production?,
        httponly: Rails.env.production?
      
    )

    render json: auth_token.payload, status: :created
  end
end

这将在客户端上设置一个 cookie,并在响应正文中返回所有令牌数据,包括一个 CSRF 令牌。

您还需要确保您的 AJAX 请求包含 cookie,默认情况下它们不包含该 cookie。使用 Axios,您可以通过设置选项 withCredentials: true 来做到这一点。对于其他库,这将是类似的。

CORS

如果您在 API 服务器上配置了 CORS,并且您应该这样做,那么您还需要在那里进行一些额外的配置。我为此使用了Rack::CORS gem,我的配置看起来像这样(config/initializers/cors.rb):

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'http://localhost:3001'
    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head],
      credentials: true
  end
end

注意credentials: true 的配置以及在origins 下指定特定主机的需要,在这种情况下* 和域列表都不起作用。

CSRF 和 XSS

基本上跨站点请求伪造是指假设您的用户已登录并具有会话 cookie,则另一个域向您的后端发出请求。因此它基于 cookie 并来自第三方域,因此无法访问您浏览器中的任何内容。

XSS,跨站点脚本是指有人设法在您的页面上运行脚本,从而在您的域上运行。这种攻击可以访问您浏览器中针对该域的任何内容。这包括 sessionStorage 和 localStorage 以及浏览器可以读取的普通 cookie。

为什么会这样

CSRF 令牌存在于会话 cookie 中,并与每个 API 请求一起作为标头发送,在保持后端无状态的同时提供对 CORS 和 XSS 的保护。

所有后端服务所要做的就是:

    验证 JWT 签名(以确保它不是被返回的伪造或操纵的会话 cookie)。 验证 exp 部分以避免 JWT 重放。 将标头 CSRF 令牌与 JWT 中的进行比较。 验证 JWT 中的范围(这将是特定于应用程序的)。

完整的 JWT 在用作 cookie 之前使用服务器私钥签名,因此无法在不检测的情况下进行操作。

所以任何 CSRF 攻击都会失败,因为它只能间接访问会话 cookie,并且无法从中读取 CSRF 令牌,因此任何请求都会失败。

任何 XSS 攻击都会失败,因为即使他们可以读取 localStorage 中的 CSRF 令牌,他们也无法获取会话 cookie。做到这一点的唯一方法是从浏览器会话向后端运行请求,虽然这可能是可能的,但这些攻击通常不是这样工作的。他们通常会尝试导出会话信息,以便他们可以从另一台服务器发出请求,但这在此处不起作用。

【讨论】:

嗨乔纳斯,你为什么使用这个位?我们只在生产中使用安全 cookie 有什么原因吗?为什么不在 staging 或 dev 中? ```安全:Rails.env.production?,httponly:Rails.env.production? ``` @bishal 您通常不希望发送安全 cookie,除非其视频 HTTPS。如果您使用 HTTP 开发应用程序,您将收到有关通过 HTTP 发送安全 cookie 的警告。假设您在生产环境中使用 HTTPS,那么现在是安全发送 cookie 的好时机。 我仍然无法真正弄清楚这种保护是如何工作的。您能否提供一些示例,说明服务器必须采取哪些措施来保护它。因为 XSS 可以代表你提出请求,所以他们可以做任何事情。

以上是关于Rails Set-Cookie on json API 响应的主要内容,如果未能解决你的问题,请参考以下文章

在 Ruby on Rails 中,如何渲染 JSON?

如何在 Ruby on Rails 中“漂亮”地格式化 JSON 输出

Ruby on Rails 6 PUT json 参数未设置

Ruby on Rails JSON 序列化

在页面上输出外部 JSON Api Ruby on Rails

Ruby on Rails,json vs js ajax 响应