前端 token 存在哪里更安全?
简化版
token 没有绝对安全的前端存储位置。localStorage 易受 XSS 窃取,Cookie 自动发送易受 CSRF,但 HttpOnly、Secure、SameSite Cookie 通常更适合高安全登录态。关键是结合 XSS、CSRF、防重放、过期刷新和服务端校验整体设计。
详细版
常见方案:
- localStorage:使用方便,但 JS 可读,XSS 风险高。
- sessionStorage:标签页级别,仍可被 XSS 读取。
- 内存变量:刷新丢失,XSS 仍可能操作当前页面。
- HttpOnly Cookie:JS 读不到,降低 token 被盗风险,但要防 CSRF。
安全设计:
- Cookie 设置 HttpOnly、Secure、SameSite。
- token 短有效期。
- refresh token 轮换。
- 服务端支持失效和风控。
- 前端做好 XSS 防护。
不要把“存哪里”当作唯一安全措施。
完整版教学
一、为什么没有完美位置
前端运行在用户浏览器中,天然不是强安全环境。只要页面存在 XSS,攻击脚本就能以用户身份执行很多操作。
localStorage 中的 token 可以被直接读取。HttpOnly Cookie 虽然读不到,但浏览器会自动带上它,CSRF 风险需要额外处理。
所以安全设计是权衡,而不是寻找绝对安全位置。
二、localStorage 的问题
localStorage 最大问题是同源 JS 可读。一旦 XSS 成功,攻击者可以读取 token 并发送到自己的服务器。
如果 token 长期有效,后果更严重。因此不建议把长期高权限 token 放 localStorage。
三、HttpOnly Cookie 的优势和代价
HttpOnly Cookie 不能被 JS 读取,可以降低 token 被直接窃取的风险。
但 Cookie 会随请求自动发送,所以要配置 SameSite,重要操作配合 CSRF Token 或 Origin 校验。
另外,跨域登录、子域名共享、移动端 WebView 等场景会让 Cookie 配置更复杂。
四、面试追问与工程落地
面试官可能问:“如果用了 HttpOnly Cookie,是不是就不怕 XSS?”
不是。XSS 虽然读不到 token,但仍可以在当前页面发起操作、修改页面、窃取非 HttpOnly 数据。因此 XSS 防护仍然必须做。
工程中推荐短期 access token、refresh token 轮换、服务端黑名单或版本号失效机制,并配合异常登录检测。
五、把登录态拆成访问、刷新和会话
高安全 Web 应用常让浏览器只持有 HttpOnly 会话 Cookie,BFF 在服务端代持下游 token;若采用 access/refresh token,也要让二者权限和寿命分离。
| 资产 | 示例寿命 | 推荐约束 | 泄露后的风险 |
|---|---|---|---|
| access token | 5–15 分钟 | 最小 scope、短期 | 短窗口内调用接口 |
| refresh token | 数天到数周 | HttpOnly、轮换、复用检测 | 可持续换取新访问权 |
| 会话 Cookie | 按业务 | HttpOnly、Secure、SameSite | 浏览器可自动携带 |
| CSRF Token | 会话或请求级 | 与会话绑定、JS 可提交 | 不能当身份 token 使用 |
例如 access token 有效 10 分钟,攻击者在第 9 分钟窃取后最多仍有约 10 分钟并不准确:它只剩约 1 分钟;真正风险取决于剩余寿命、scope 和服务端吊销能力。
HttpOnly 防的是“脚本读走凭证”,不是“恶意脚本借当前浏览器发操作”;XSS 仍能调用站内接口和篡改页面。
六、刷新轮换、Cookie 范围与退出闭环
Refresh token 每次使用后签发新值并废弃旧值。若旧值再次出现,说明可能被复制,应吊销整条 token family 并要求重新登录;否则长寿命 refresh token 一旦泄露,可持续维持会话。
Cookie 的 Domain 和 Path 主要决定发送范围,不是可靠的权限边界。应使用尽量窄的 host-only Cookie、Secure、HttpOnly、合适 SameSite,并避免不可信子域与高权限会话共享作用域。
登录 → 短期 access + 可轮换 refresh
access 过期 → refresh 换新 pair → 旧 refresh 作废
检测旧 refresh 复用 → 吊销 family → 重新认证
退出登录不能只清前端变量,还要让服务端会话或 refresh token 失效。密码修改、设备丢失、管理员封禁也应触发服务端吊销,并记录设备、IP 异常和最近活动供风控判断。
跨标签页同步退出也要纳入设计:一个标签页吊销会话后,其他标签页应尽快停止敏感请求并回到登录态,不能继续展示可操作的陈旧界面。
七、常见误区与追问
- 误区:HttpOnly Cookie 能让页面免疫 XSS。 脚本虽读不到 Cookie,仍可借用户会话执行操作。
- 误区:localStorage 不自动发送,所以一定更安全。 任意同源 XSS 可直接读取并外传长期 token。
- 误区:JWT 无状态就无法主动失效。 可用短寿命、版本号、吊销表或会话层实现失效,代价是引入状态和查询。
- 追问:为什么 BFF 模式更适合高安全 Web? 浏览器只持 HttpOnly 会话,服务端代持和使用下游 token,减少 JS 可读凭证。
- 追问:SameSite 后还要 CSRF Token 吗? 高风险 Cookie 会话通常仍组合 Token 和来源校验,覆盖同站与配置边界。
- 追问:refresh token 为什么要轮换? 每次使用废弃旧值,可检测复制凭证的复用行为并快速止损。
- 追问:退出登录只删除 Cookie 是否够? 不够;服务端凭证仍有效时,已复制的 token 还能继续使用。
八、加强记忆
- 没有绝对位置:每种存储都在 XSS、CSRF、持久性之间权衡。
- Web 首选思路:高安全场景倾向 HttpOnly Cookie 或 BFF,减少 JS 可读凭证。
- 缩短价值:access 短寿命、最小 scope,refresh 严格保护并轮换。
- 纵深防护:Cookie 配 Secure/SameSite,状态修改配 CSRF 防线。
- 服务端可控:支持 family 吊销、设备退出、密码变更和异常检测。
- 边界牢记:存储方案不替代 XSS 修复与每个接口的授权校验。