共计 1944 个字符,预计需要花费 5 分钟才能阅读完成。
背景痛点
在前后端分离架构中,我们经常需要通过 a 标签进行页面跳转,同时携带身份验证 token。传统的方式是直接将 token 作为 URL 参数传递,例如:

<a href="/dashboard?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."> 进入控制台 </a>
这种方式存在严重的安全隐患:
- Referer 泄露 :当用户从目标页面跳转到其他站点时,浏览器会将完整 URL(包含 token)通过 Referer 头发送
- 历史记录暴露 :token 会保留在浏览器历史记录中,可能被恶意软件或共用电脑的其他用户获取
- 日志记录 :服务器访问日志会记录完整 URL,增加了 token 泄露风险
方案对比
1. URL 参数编码方案
通过加密和编码处理 token,降低直接暴露的风险:
- 使用 Web Crypto API 对 token 进行加密
- 将加密结果转换为 Base64 编码
- 添加到 URL 参数时进行 URL 安全编码
// 加密函数示例
async function encryptToken(token, secretKey) {const encoder = new TextEncoder();
const key = await crypto.subtle.importKey(
'raw',
encoder.encode(secretKey),
{name: 'AES-GCM'},
false,
['encrypt']
);
const iv = crypto.getRandomValues(new Uint8Array(12));
const encrypted = await crypto.subtle.encrypt({name: 'AES-GCM', iv},
key,
encoder.encode(token)
);
return {iv: btoa(String.fromCharCode(...iv)),
data: btoa(String.fromCharCode(...new Uint8Array(encrypted)))};
}
优点 :
– 实现简单,兼容性好
– 不需要额外存储
缺点 :
– 仍然会在历史记录中留下痕迹
– 需要服务端配合解密
2. SessionStorage 中转方案
- 在点击 a 标签时拦截默认行为
- 将 token 存入 sessionStorage
- 使用 window.location 进行跳转
- 目标页面从 sessionStorage 读取 token
React 示例 :
function SafeLink({to, token, children}) {const handleClick = (e) => {e.preventDefault();
sessionStorage.setItem('tempAuthToken', token);
window.location.href = to;
};
return <a href={to} onClick={handleClick}>{children}</a>;
}
跨域处理 :
- 同域下可直接使用
- 跨域时需要目标域通过 postMessage 接收 token
3. 服务端 302 跳转 +HTTP 头注入
sequenceDiagram
客户端 ->> 服务端: 点击 a 标签访问 /protected
服务端 ->> 客户端: 302 重定向到 /login?redirect=/protected
客户端 ->> 认证服务: 携带 cookie 自动认证
认证服务 ->> 客户端: 302 重定向回 /protected 带一次性 token
客户端 ->> 服务端: 访问 /protected 带 token 头
服务端 ->> 客户端: 返回受保护资源
优点 :
– token 不会出现在 URL 中
– 适合 SSO 场景
缺点 :
– 需要服务端配合
– 实现复杂度较高
安全考量
CSRF 防护
- URL 参数方案 :需要配合 SameSite Cookie 和 CSRF Token
- SessionStorage 方案 :不受 CSRF 影响,但需防范 XSS
- HTTP 头方案 :依赖 SameSite Cookie
Token 刷新机制
- 设置较短的有效期(如 5 分钟)
- 跳转后立即使用并清除
- 提供刷新接口获取新 token
避坑指南
- iOS Safari 隐私模式 :sessionStorage 在隐私模式下可能无法正常工作,需要降级到 URL 参数方案
- Base64 编码陷阱 :某些框架会自动解码 URL 参数,导致加密数据损坏
- 302 循环 :当认证服务配置错误时可能导致无限重定向
延伸思考
JWT 的无状态特性与这些方案都能良好配合,但需要考虑:
– JWT 体积较大,不适合直接放入 URL
– 可以改用短期 JWT 作为跳转令牌
– 结合 JWT 的签名特性可以增强防篡改能力
在实际项目中,建议根据安全需求选择合适方案。对于金融级应用,推荐使用服务端 302 跳转;对内部管理系统,SessionStorage 方案更为便捷。无论哪种方案,都应定期进行安全审计,确保 token 不会意外泄露。
正文完
