1. 前置
在讨论JWT的存储位置前,我们首先需要了解:
- JWT主要用于验证数据完整性和来源可靠性,而非提供消息的机密性。由于JWT可能被解码,因此不建议直接存储敏感数据。
- 在浏览器环境中,安全性相对较低,即使采用风险较低的方案,但是相比于后端等环境仍可能面临更高的潜在威胁。针对安全性需求较高的场景,推荐增加实施多因素认证(MFA)。
2. 存储环境对比
在浏览器环境中,常见的持久化存储位置包括:LocalStorage, SessionStorage, Cookie, 其中 Cookie 有一个特殊的 HttpOnly Cookie,以下是几个存储环境的特性对比:
特性 | LocalStorage | SessionStorage | Cookie | HttpOnly Cookie |
---|---|---|---|---|
数据持久性 | 持久存储,除非手动清除或用户清理数据 | 会话存储,关闭页面会话后数据被清除 | 可设置过期时间,默认为会话cookie | 同Cookie |
过期控制 | 无 | 无 | 可设置过期时间 | 可设置过期时间 |
存储容量 | 通常约5MB | 通常约5MB | 较小,通常4KB | 同Cookie |
数据共享 | 不随HTTP请求发送 | 不随HTTP请求发送 | 随HTTP请求发送 | 随HTTP请求发送,但不可通过JavaScript访问 |
访问限制 | 可通过JavaScript访问 | 可通过JavaScript访问 | 可通过JavaScript访问 | 不可通过JavaScript访问 |
自动发送 | 不自动发送 | 不自动发送 | 自动随请求发送 | 自动随请求发送 |
安全性 | 存在 XSS 攻击风险 | 存在 XSS 攻击风险 | 存在 XSS, CSRF 攻击风险 | 存在 CSRF 攻击风险;JS 无法访问,包括自己的 |
设置/获取方法 | localStorage.setItem() , localStorage.getItem() | sessionStorage.setItem() , sessionStorage.getItem() | document.cookie | document.cookie |
适用场景 | 存储大量数据,非敏感数据 | 临时存储会话数据 | 用户认证,跟踪状态 | 安全的用户认证,减少XSS风险 |
3. 具体存储方案探讨
3.1. 前置说明
- 此章节关于 Cookie 的讨论均基于 SameSite=Lax 属性。
- HttpOnly Cookie 禁止 JS 获取 Cookie,所以 React, Vue 等框架也无法获取 JWT 的值。
*虽然 SameSite=Lax 大幅降低了 CSRF 风险,但是 SameSite-Lax 在预加载等场景仍可能存在 CSRF 风险。
3.2. 具体方案以及对比
方案一:使用 Access Token 和 Refresh Token,在 LocalStorage 存放短期的 Access Token,再使用 HttpOnly Cookie 中存放 Refresh Token。
- 在安全性与兼容性中取平衡,
- 优点:
- LocalStorage 中存放的 Access Token 可以便捷的放到 Header authentication 中,兼容大部分主流框架;
- 同时 Access Token 有效期较短,可以一定程度上降低泄露的风险;
- Refresh Token 放在 HttpOnly Cookie 中可以有效降低 XSS 攻击风险;
- 开发中可以分步开发,先实现简单的 Access Token 之后再实现 Refresh Token。
- 缺点:
- 前后端需要额外维护 Refresh Token;
- Access Token 相对存在更高的 XSS 攻击风险;
- LocalStorage 无法控制 token 在本地存储的时间。
方案二:使用 HttpOnly Cookie 存放 JWT。
- 优点:
- XSS 风险较低;
- 可以有效控制 JWT 的存放时间。
- 缺点:
- SameSite=Lax 在预加载等场景仍可能存在 CSRF 风险;
- 前端 JS 无法实现获取 JWT,所以无法将 JWT 存放到 Header authentication 中,所以与第三方前后端框架交互存在一定程度的兼容性;
- 前期开发成本相对较高,需要手动实现相关 JWT 的解析、封装和管理。
4. 附言
综合而言,在浏览器环境中安全性相对较低,使用 JWT 的目的之一,就是为了简化认证流程,多应用单点登录,过分的依赖于 JWT 不会被窃取,强化 JWT 来源的识别,反而违背了 JWT 的设计。针对安全性需求较高的场景,推荐增加更多的安全校验如 IP 地址识别,设备识别等,以及实施多因素认证(MFA)。
5. 参考
- Token 放 localStorage?sessionStorage?還是 Cookie?| 是 Ray 不是 Array: https://israynotarray.com/information-security/20230516/18406287/
- authentication - Store Auth-Token in Cookie or Header? - Information Security Stack Exchange: https://security.stackexchange.com/questions/180357/store-auth-token-in-cookie-or-header
- authentication - Secure HttpOnly Cookie or Header field for auth token securing an API? - Information Security Stack Exchange: https://security.stackexchange.com/questions/119892/secure-httponly-cookie-or-header-field-for-auth-token-securing-an-api
- Using HTTPOnly Cookies to Strengthen User Authentication - Technology - Notarize | Notarize Blog: https://www.notarize.com/blog/using-httponly-cookies-to-strengthen-user-authentication
- 本作品采用 署名-相同方式共享 4.0 国际(CC BY-SA 4.0 DEED) 许可