javascript - 如何使用 Next.js 和 Rails 后端安全地存储 JWT?
问题描述
我正在尝试在 Next.js 前端和 Rails API 后端之间实现身份验证,但我很难理解如何安全地正确执行此操作。
我在 rails 端使用jwt-sessions gem,它在登录时返回一个access_token
、 arefresh_token
和一个csrf
令牌。csrf
只能通过标头发送,并且对于所有非 GET 或 HEAD 请求都是必需的。access
andrefresh
可以通过标头或cookie给出。
我可以实现后端以在 JSON 响应中返回所有令牌,或设置 cookie,或两者兼而有之。
问题是,客户端我看不到存储这些令牌的真正方法是:
- 安全的
- 在 SSR 期间以及在浏览器中可用
这是我看到的选项
选项 1:服务器设置 httpOnly Cookie
这是jwt-sessions
宝石推荐的。将 CSRF 保存在 localStorage 中,而将其他令牌保存在服务器设置的 httpOnly cookie 中。
这似乎是最安全的,但是 SSR viagetInitialProps
根本不起作用,因为它无法通过fetch
. 我什至不能手动发送它们,因为我在 JS 中看不到它们。
选项 2:非 httpOnly Cookie
这就是下一个官方示例似乎要做的事情(尽管使用了一个可能是无状态的令牌)
让服务器或浏览器设置没有httpOnly 的 cookie。
我可以通过 SSR 访问它,但这不会让我接受 XSS 吗?
选项 3:使用浏览器存储
只需将所有标记放入localStorage
和/或sessionStorage
. 这似乎是最糟糕的选择,因为它在 SSR 中不起作用,而且据我所知并不安全。
???
我错过了什么吗?是非httpOnly,就像在官方的例子中,好吗?有更好的方法吗?还是我必须忽略 SSR(因此是 Next.js 的杀手级功能之一)?
解决方案
让我们检查每个令牌以及它将在哪里使用。Cookie 只能提供给设置它们的服务器,因此任何 cookie 都需要由使用它的服务器设置。
refresh
令牌
如果访问令牌过期,刷新令牌将提交给jwt-sessions
身份验证服务器以获取新access
的令牌。csrf
由于刷新令牌既来自认证服务器,又在认证服务器上使用,所以可以被认证服务器设置为HttpOnly
cookie
Set-Cookie: refresh-token=...; domain=rails-backend.example.com; secure; HttpOnly
access
令牌
访问令牌将有两种使用方式,它将由 next.js 客户端呈现给 rails 后端,并由 next.js 服务器端使用它来调用 rails 后端到服务器端渲染页面通过getInitialProps
.
从客户端向 Rails 后端提供访问令牌很容易。jwt-sessions
身份验证服务器与 rails 后端运行在同一台服务器上,因此身份验证服务器可以设置cookie HttpOnly
。
Set-Cookie: access-token=...; domain=rails-backend.example.com; secure; HttpOnly
从 next.js 服务器端呈现它更加困难,要到达那里,客户端需要将访问令牌发送到 next.js 服务器端。标题将是最初呈现它的适当方式。并且要将其发送到 next.js 服务器端,客户端需要包含在来自身份验证服务器的 json 响应中的访问令牌。
{
'access': "..."
}
Host: next-js-server-side.example.com
X-Rails-Backend-Access-Token: ...
一旦 next.js 服务器端拥有访问令牌,它就可以设置一个HttpOnly
cookie 以使访问令牌可用于未来的请求。
Set-Cookie: rails-backend-access-token=...; domain=next-js-server-side.example.com; secure; HttpOnly
csrf
令牌
csrf 令牌用于保护对 rails 后端的请求免受跨站点伪造请求。它需要由任何向 Rails 后端发出请求的东西呈现,包括客户端和服务器端。
客户端将从身份验证服务器获取 csrf 作为 json 有效负载的一部分,因为这是将其传递给客户端的唯一安全方式。
{
'csrf': "..."
}
客户端现在可以使用它向 Rails 后端发出请求,但不会持久存储。
要将 csrf 令牌获取到 next.js 服务器端,客户端会将其作为标头发送
Host: next-js-server-side.example.com
X-Rails-Backend-CSRF-Token: ...
next.js 服务器端可以转身并设置一个HttpOnly
cookie 以使 csrf 令牌可用于未来的请求。
Set-Cookie: rails-backend-csrf-token=...; domain=next-js-server-side.example.com; secure; HttpOnly
这个cookie对于跨站伪造请求到rails后端是没有用的,因为它只呈现给next-js服务器端,根本不呈现给rails后端。
next.js 服务器端可以将此令牌返回给客户端,只要它以一种不会被发起跨站点伪造攻击的站点劫持的方式执行。
<input type="hidden" id="rails-backend-csrf-token" value="...">
next.js 的跨站请求伪造
next.js 服务器端需要提供自己的跨站点伪造保护。它不能依赖HttpOnly
上面设置的 cookie,因为它会在跨站点请求中呈现。
推荐阅读
- api - NestJS:在 POST 请求中将 @Param 和 body 值设置为 DTO
- ios - 金属中的延迟屏幕空间贴花
- python - 如何在 Tkinter 中将 Treeview 数据保存为 excel 文件?
- jenkins - Jenkins 声明式:具有多个代理的 Kubernetes 插件
- kubernetes - 如何改变 EKS 中 kube-scheduler 的行为?
- c# - 将 int 提升为 long 时会收到警告吗?
- android - 带和不带下划线变量视图绑定的目的
- java - 为外部存储库创建 Jacoco 报告
- typescript - Typescript 中是否有一种方法可以模拟在网站表单上按 Enter 时按下的 Tab 键?
- delphi - FileExists 后 RenameFile 中的访问被拒绝