flawopen.com/参考/JWT 与 HttpOnly Cookie
localStorage 中的 JWT 与 HttpOnly Cookie:哪个更安全?
认证指南
简短回答
对许多 Web 应用来说,由服务器管理并通过 HttpOnly Cookie 传递的会话是稳妥的默认起点。JavaScript 无法读取该 Cookie,因此更难直接窃取其中的凭据;但它不会消除 XSS:同源注入脚本仍可能发起已认证请求,并读取页面可访问的数据。
安全上的取舍
| 存储 / 传递 | XSS 风险 | CSRF 行为 | 撤销 |
|---|---|---|---|
localStorage bearer token | 同源 JavaScript 可读取;XSS 可窃取令牌或以用户身份操作。 | 不会自动附加到跨站请求;XSS 和客户端 CSRF 仍是风险。 | 若不检查撤销状态,自包含 JWT 可能一直有效到过期。 |
HttpOnly cookie | JavaScript 无法读取 Cookie 值;XSS 仍能发起已认证请求。 | 按 Cookie 规则自动发送;SameSite 只是 CSRF 防护的一层。 | 不透明会话可在服务器端失效;JWT Cookie 仍需单独的撤销策略。 |
推荐架构
- ✓将会话标识符存放在
HttpOnly; Secure; SameSite=LaxCookie 中。 - ✓不要将持久性认证令牌存放在
localStorage或sessionStorage中。
区分令牌格式、存储方式和会话状态
JWT 是一种令牌格式;localStorage 和 Cookie 是浏览器中的存储与传递机制。JWT 可以存放在两者任一处。Cookie 中的不透明会话标识符通常指向服务器端会话状态。“JWT 还是 Cookie”并不是对等方案之间的直接比较。
不同选择会改变什么
浏览器不会自动把 localStorage 的值附加到跨站请求中,但同源 XSS 仍能读取 bearer 令牌或通过应用执行操作。Cookie 按浏览器规则自动发送;HttpOnly 只是不让 JavaScript 读取其值,并不能阻止注入脚本利用已登录页面。SameSite=Lax 是一层 CSRF 防护,并非完整保证:安全方法的顶层导航和 same-site 请求仍需考虑。不要通过 GET 修改状态,并根据威胁模型使用适当的 CSRF 防护,例如验证令牌和/或 Origin 检查。
撤销能力取决于服务器状态和令牌验证方式,而非存储位置。删除服务器会话记录即可使其失效。若不检查撤销状态,自包含 JWT 可能一直有效到过期;缩短有效期能缩小窗口,但不能消除它。
实用的默认方案
- ✓对于自有 Web 应用,在架构适用时优先考虑不透明的服务器端会话或 Backend-for-Frontend(BFF)。
- ✓会话 Cookie 设置
Secure、HttpOnly、经过选择的SameSite、Path=/;尽可能不设置Domain,并考虑__Host-前缀。 - ✓根据威胁模型,为状态变更请求使用 CSRF 令牌和/或 Origin 验证;绝不通过
GET修改状态。 - ✓如果浏览器必须持有 JWT,应采用短有效期,定义注销和撤销行为,并防止 XSS。Cookie 存储不能替代授权检查。