React+NestJS中Access/Refresh Token存储方案选型及子域共享疑问
令牌存储方案对比与子域适配分析
方案1:Access + Refresh Token 均存入Cookie
优势
- 自动携带与子域共享便捷:只要设置Cookie的
Domain为父域(如.example.com),所有子域的请求都会自动携带令牌,无需前端额外处理,完美适配子域场景。 - 更高的安全性(配置得当):给Cookie添加
HttpOnly、Secure、SameSite=Strict/Lax属性:HttpOnly阻止XSS脚本窃取令牌;Secure确保仅通过HTTPS传输;SameSite大幅降低CSRF攻击风险(跨站请求不会携带Cookie)。
- 无需前端手动管理令牌携带:同域/子域的API请求会自动带上Cookie,减少前端代码复杂度。
劣势
- CSRF风险仍存在(若配置不当):如果
SameSite未正确设置(如设为None),或浏览器不支持SameSite(极少旧版本),仍可能遭遇CSRF攻击,需配合后端CSRF令牌验证(如请求头携带X-CSRF-Token)补充防护。 - 极端环境兼容性问题:极少数特殊嵌入式浏览器可能不支持Cookie,但现代主流浏览器均无此问题。
方案2:Refresh Token存Cookie,Access Token存localStorage
优势
- 规避Access Token的CSRF风险:localStorage中的令牌不会自动携带到请求,需前端手动在请求头添加
Authorization: Bearer <token>,跨站请求无法利用CSRF窃取令牌权限。 - 前端可直接操作令牌:若需在JS中直接使用Access Token(如调用第三方API),此方案更灵活。
劣势
- XSS风险更高:XSS脚本可直接读取localStorage中的Access Token,进而伪造请求窃取权限(相比方案1的
HttpOnlyCookie,安全性更低)。 - 子域共享困难:localStorage遵循严格的域隔离规则,子域无法直接访问主域的localStorage。若要实现共享,需通过
postMessage在主域与子域页面间传递令牌,或借助iframe桥接,增加了前端复杂度与潜在安全风险。 - 前端需手动管理令牌:需编写请求拦截器统一添加Authorization头,页面刷新后需主动调用Refresh Token接口获取新的Access Token,代码维护成本更高。
方案选择建议
- 优先选方案1:如果你的Web应用是同域/子域架构,且无需在JS中直接读取Access Token,方案1在安全性、开发便捷性、子域适配上均更优。只要正确配置Cookie属性(
HttpOnly、Secure、SameSite=Strict/Lax),再配合后端CSRF验证,就能有效抵御常见攻击。 - 选方案2的场景:若必须在前端JS中直接使用Access Token(如对接第三方服务),或需要兼容极少数不支持Cookie的环境,可考虑方案2,但需加强XSS防护(如内容安全策略CSP、输入过滤),并额外处理子域令牌共享的问题。
关于子域环境下方案2的适用性
方案2默认不适用于子域环境,因为localStorage无法跨子域共享。若要适配,需额外做以下处理:
- 在主域页面中存储Access Token,子域页面通过
postMessage向主域请求令牌,主域验证身份后返回; - 使用iframe嵌入主域页面作为桥接,子域通过iframe间接访问主域的localStorage;
- 放弃localStorage,将Access Token存入非
HttpOnly的Cookie(但会引入XSS风险,需谨慎)。
这些方法均会增加开发复杂度与安全风险,因此子域场景下方案1是更省心的选择。
内容的提问来源于stack exchange,提问作者Shawn
相关产品推荐
相关产品推荐

