javascript - 如何使用 Next.js 和 Rails 后端安全地存储 JWT?

标签 javascript ruby-on-rails authentication jwt next.js

我正在尝试在 Next.js 前端和 Rails API 后端之间实现身份验证,但我很难理解如何安全地正确地执行此操作。

我正在使用 jwt-sessions rails 端的 gem,它在登录时返回一个 access_token、一个 refresh_token 和一个 csrf token 。 csrf 只能通过 header 发送,并且是所有非 GET 或 HEAD 请求所必需的。 accessrefresh 可以通过 header 由 cookie 提供。

我可以实现后端以返回 JSON 响应中的所有标记,或设置 cookie,或两者兼而有之。

问题是,客户端我看不到存储这些 token 的真正方法是:

  1. 安全
  2. 在 SSR 期间以及在浏览器中可用

这是我看到的选项

选项 1:服务器设置 httpOnly Cookies

这是 jwt-sessions gem 推荐的。将 CSRF 保存在 localStorage 中,但将其他标记保存在服务器设置的 httpOnly cookie 中。

这似乎是最安全的,但是通过 getInitialProps 的 SSR 根本不起作用,因为它无法通过 fetch 发送 cookie。我什至无法手动发送它们,因为我在 JS 中看不到它们。

选项 2:非 httpOnly Cookie

这就是official next example似乎可以(尽管有一个单一的,可能是无状态的 token )

让服务器或浏览器设置 cookie 而不 httpOnly。

我可以通过 SSR 访问它,但这不是让我容易受到 XSS 攻击吗?

选项 3:使用浏览器存储

只需将所有 token 放入 localStorage 和/或 sessionStorage。这似乎是最糟糕的选择,因为它在 SSR 中不起作用,而且据我所知也不安全。

????

我错过了什么吗?是不是httpOnly,就像官方的例子,好吗?有更好的方法吗?还是我必须忽略 SSR(以及 Next.js 的 killer 级功能之一)?

最佳答案

让我们检查每个标记及其使用位置。 Cookie 只能呈现给设置它们的服务器,因此任何 cookie 都需要由使用它的服务器设置。

刷新 token

如果访问 token 过期,刷新 token 将提交给jwt-sessions 身份验证服务器以获取新的accesscsrf token .由于刷新 token 既来自认证服务器,又在认证服务器上使用,因此认证服务器可以将其设置为HttpOnly cookie

Set-Cookie: refresh-token=...; domain=rails-backend.example.com; secure; HttpOnly

访问 token

访问 token 将以两种方式使用,它将由 next.js 客户端呈现给 rails 后端,并由 next.js 服务器端使用它来调用 rails 后端到服务器- 通过 getInitialProps 呈现页面。

从客户端向 Rails 后端提供访问 token 很容易。 jwt-sessions 身份验证服务器与 Rails 后端运行在同一台服务器上,因此身份验证服务器可以设置一个 HttpOnly cookie。

Set-Cookie: access-token=...; domain=rails-backend.example.com; secure; HttpOnly

从 next.js 服务器端呈现它更加困难,要将其发送到那里,客户端需要将访问 token 发送到 next.js 服务器端。标题将是最初展示它的合适方式。并将其发送到 next.js 服务器端,客户端需要包含在来自身份验证服务器的 json 响应中的访问 token 。

{
    'access': "..."
}
Host: next-js-server-side.example.com
X-Rails-Backend-Access-Token: ...

一旦 next.js 服务器端有了访问 token ,它就可以设置一个 HttpOnly cookie 来为将来的请求提供访问 token 。

Set-Cookie: rails-backend-access-token=...; domain=next-js-server-side.example.com; secure; HttpOnly

csrf token

csrf token 用于保护请求到 rails 后端免受跨站点伪造请求。它需要由任何向 Rails 后端发出请求的东西来呈现,包括客户端和服务器端。

客户端将从身份验证服务器获取 csrf 作为 json 有效负载的一部分,因为这是将其发送到客户端的唯一安全方式。

{
    'csrf': "..."
}

客户端现在可以使用它向 Rails 后端发出请求,但它不会持久存储。

要获取csrf token到next.js服务器端,客户端会把它作为header发送

Host: next-js-server-side.example.com
X-Rails-Backend-CSRF-Token: ...

next.js 服务器端可以轻松地转身并设置一个 HttpOnly cookie 以使 csrf token 可用于 future 的请求。

Set-Cookie: rails-backend-csrf-token=...; domain=next-js-server-side.example.com; secure; HttpOnly

这个cookie对于向rails后端的跨站伪造请求是没有用的,因为它只呈现给next-js服务器端,根本不呈现给rails后端。

next.js 服务器端可以将此 token 返回给客户端,只要它不会被发起跨站点伪造攻击的站点劫持即可。

<input type="hidden" id="rails-backend-csrf-token" value="...">

next.js 的跨站请求伪造

next.js 服务器端需要提供它自己的跨站点伪造保护。它不能依赖上面设置的 HttpOnly cookie,因为它将在跨站点请求中显示。

关于javascript - 如何使用 Next.js 和 Rails 后端安全地存储 JWT?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57898011/

相关文章:

zend-framework - Zend 框架 : How to redirect to original url after login?

javascript - 我有一个有效的 json 但我不断收到 "syntaxerror json.parse unexpected end of data at line 1"!

javascript - 用子高度扩展父高度

ruby-on-rails - 如何在 Rails 助手中使用 jQuery

ruby-on-rails - Sphinx 守护进程返回错误 : index product_core: INTERNAL ERROR: incoming-schema mismatch. 仅在登台服务器上

javascript - 轮播内幻灯片的延迟加载内容(内容是 oEmbeds/iframes)

authentication - 具有基本身份验证的 Solr 4

javascript - webpack 以与其他 js 文件相同的方式解析 node_modules

javascript - 在没有 TypeScript Transpiler 的情况下使用 Angular 2

PHP 登录全部大写