Rails Set-Cookie on json API 响应

csi*_*csi 5 api cookies json ruby-on-rails jwt

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

# response from API  
render json: {user: "user", token: "token_string"}, status: :created
Run Code Online (Sandbox Code Playgroud)

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

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

Jon*_*son 14

这是我的跨域 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
Run Code Online (Sandbox Code Playgroud)

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

您还需要确保您的 AJAX 请求包含 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
Run Code Online (Sandbox Code Playgroud)

需要注意的配置credentials: true以及需要指定下一个特定的主机origins,既不*也不域的列表会在这种情况下工作。

CSRF 和 XSS

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

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

为什么这有效

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

任何后端服务所要做的就是:

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

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

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

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