知识分享平台项目复习第二天:登录模块中的双令牌与刷新安全(2)

项目复习第二天:从 Token 存储风险理解 XSS、CSRF 与 CORS

复习日期:2026-09-14

当前主线:认证安全------登录闭环

一、为什么登录模块会遇到 XSS、CSRF 和 CORS

第一天复习登录模块时,我已经理解了 Access Token、Refresh Token、Redis jti 白名单、Rotation 和登出空窗期。继续讨论前端令牌存储时,又出现了一个新的问题:当前项目把 Access Token 和 Refresh Token 都保存在 localStorage 中,这样虽然实现简单,但需要考虑浏览器环境中的安全风险。

当前项目的前端会从 localStorage 读取 Access Token,并主动加入请求头:

复制代码
Authorization: Bearer <access-token>

这让我需要区分三个经常同时出现、但职责完全不同的概念:

  • XSS:攻击者的代码进入目标网站并执行。

  • CSRF:攻击者借助浏览器自动携带的登录凭证执行操作。

  • CORS:浏览器控制跨源页面能否读取接口响应。

它们都与浏览器安全有关,但 XSS 和 CSRF 是攻击方式,CORS 是浏览器的跨源访问控制机制。

二、XSS:攻击者的代码进入了目标网站

XSS 全称是 Cross-Site Scripting,即跨站脚本攻击。

它的核心不是"攻击者从外部调用了接口",而是攻击者设法让恶意 JavaScript 在知享页面中运行。代码虽然由攻击者编写,但浏览器会把它当成知享网站自身的代码。

例如,如果一个恶意脚本能够在当前页面中执行,它可能读取:

复制代码
localStorage.getItem("zhiguang_auth_tokens")

当前项目把 Access Token 和 Refresh Token 都存放在这个位置。因此一旦发生 XSS,恶意脚本可能读取双令牌,将它们发送给攻击者,或者直接调用知享接口冒充当前用户。

XSS 脚本还可能:

  • 修改页面显示内容;

  • 读取用户在页面中输入的信息;

  • 调用发布、修改资料等业务接口;

  • 读取非 HttpOnly Cookie;

  • 窃取页面中其他可以被 JavaScript 访问的数据。

React 默认会转义普通文本,但这不代表 React 项目天然不会出现 XSS。不安全的 HTML 渲染、DOM 操作、第三方脚本或其他注入入口仍然可能产生风险。

三、CSRF:攻击者借用了浏览器自动携带的身份

CSRF 全称是 Cross-Site Request Forgery,即跨站请求伪造。

它通常与 Cookie 认证相关,因为 Cookie 可能由浏览器自动携带。攻击者不一定能读取用户的 Cookie,但可以诱导用户浏览器向目标网站发送请求。

典型过程是:

复制代码
用户已经登录知享,浏览器保存了登录 Cookie
→ 用户访问 evil.com
→ evil.com 诱导浏览器向知享发送修改资料或注销请求
→ 浏览器可能自动携带知享的 Cookie
→ 后端误以为这是用户主动执行的操作

CSRF 的目标通常是让请求产生副作用。攻击者不一定需要看到响应内容,只要修改资料、退出登录或其他敏感操作已经执行,攻击目的就可能达到。

当前项目主要使用 localStorage + Authorization。攻击者网站不能直接读取知享域名下的 localStorage,也就不知道用户的 Access Token,无法主动构造正确的 Authorization 请求头。因此,这种方式不像 Cookie 认证那样容易受到传统 CSRF,但主要风险会转向 XSS 窃取 Token。

四、CORS:控制跨源页面能否读取响应

CORS 全称是 Cross-Origin Resource Sharing,即跨源资源共享。

一个源由三部分组成:

复制代码
源 = 协议 + 域名 + 端口

只要其中一项不同,就属于不同源。例如:

复制代码
https://zhiguang.example
https://evil.example

以及:

复制代码
http://localhost:5173
http://localhost:8080

浏览器默认通过同源策略限制一个页面读取其他源的数据。CORS 是服务器通过响应头告诉浏览器,哪些来源的 JavaScript 可以读取自己的响应。

CORS 不是:

  • 用户认证机制;

  • 接口授权机制;

  • 服务端防火墙;

  • XSS 防护;

  • 完整的 CSRF 防护。

CORS 主要限制攻击者页面是否能够读取响应,但不能保证所有跨源请求都不会发送。某些请求可能已经携带 Cookie 到达后端并产生副作用,只是浏览器最终不允许攻击者页面读取响应。

curl、Postman 和服务端程序也不受浏览器 CORS 规则限制,因为 CORS 是浏览器执行的安全机制。

五、一次跨源判断的误区

考虑这样一个场景:恶意代码运行在 evil.com,它读不到知享的 localStorage,但用户浏览器会自动携带知享的登录 Cookie。攻击者诱导浏览器向知享发送修改资料请求。

这个场景属于 CSRF。但我最开始认为:"这是用户本地浏览器发送的请求,所以没有跨源。"

这个判断是错误的。请求是不是跨源,不取决于它是不是由用户本地浏览器发送,而取决于发起请求的页面源与目标接口源是否相同。

这里的关系是:

复制代码
发起页面源:evil.com
目标接口源:zhiguang.example

两个源不同,所以请求仍然是跨源请求。

纠正后的理解是:

CORS 主要决定攻击者页面能否读取知享接口的响应,但请求可能已经携带 Cookie 到达后端。即使攻击者读不到响应,退出登录、修改资料等副作用也可能已经产生。

六、HttpOnly 为什么只能降低 XSS 危害

当 Refresh Token 已经保存在 HttpOnly Cookie 中,但知享页面仍然发生 XSS 时,恶意 JavaScript 不能直接读取和复制 Refresh Token,但仍然可以以当前用户身份调用接口,在被攻击的页面中发送请求并冒充用户执行操作。

这说明 HttpOnly 解决的是 Cookie 内容被 JavaScript 直接读取的问题,而不是阻止页面中的恶意脚本执行操作。

HttpOnly 保护的是 Cookie 内容的机密性:JavaScript 不能通过 document.cookie 直接读取和复制 Refresh Token。但是浏览器仍然可以在符合条件的请求中自动携带 Cookie。因此,XSS 脚本虽然难以把 Refresh Token 复制到攻击者自己的设备,却仍然可以在当前页面中调用修改资料、发布内容或刷新 Token 等接口。

所以:

HttpOnly 可以降低 Refresh Token 被 XSS 直接窃取的风险,但不能阻止恶意脚本在当前登录页面中操作用户账号。

七、XSS、CSRF 与 CORS 的最终区分

概念 攻击代码的位置 利用的条件 主要风险
XSS 目标网站页面内部 网站执行了恶意脚本 读取 Token、修改页面、冒充用户
CSRF 攻击者网站 浏览器自动携带 Cookie 借用户身份执行有副作用的操作
CORS 不是攻击类型 浏览器的跨源读取规则 决定跨源 JavaScript 能否读取响应

可以用下面三句话快速记忆:

  • XSS 是攻击者已经混进了目标网站。

  • CSRF 是攻击者借用了用户浏览器携带的身份。

  • CORS 是浏览器控制外部页面能否读取目标网站的响应。

对于当前项目:

复制代码
双令牌存入 localStorage
→ 主要关注 XSS 读取 Token

Refresh Token 改为 HttpOnly Cookie
→ 降低 Refresh Token 被直接读取的风险
→ 但需要额外关注 CSRF

八、Spring Security 认证链路

回到登录闭环后,当前对 Access Token 如何经过 Spring Security 到达 Controller 的理解如下:

目前已经确认的内容是:

  • Access Token 由 JwtDecoder 验签。

  • permitAll() 不等于跳过整个安全过滤器链。

  • 401 表示请求没有完成认证,例如 Token 缺失、过期、格式错误或签名错误。

  • 403 表示认证已经成功,但当前用户权限不足。

目前对Spring Security 认证完整链路的理解不完整,以下是Access Token 经过 Spring Security 到达 Controller 的完整流程:

复制代码
请求携带 Authorization: Bearer <Access Token>
→ 进入 SecurityFilterChain
→ Spring Security 提取 Bearer Token
→ JwtDecoder 校验 Token
→ 校验成功后创建 Authentication
→ 将 Authentication 放入 SecurityContext
→ 执行授权判断
→ 通过后执行 Controller

九、第二天复习结果

已达到基础复述要求

  • XSS 的执行位置以及它对 localStorage Token 的风险。

  • CSRF 利用浏览器自动携带 Cookie 产生副作用。

  • CORS 主要控制跨源响应读取,不能替代 CSRF 防护。

  • HttpOnly 能降低 Refresh Token 被直接读取的风险,但不能彻底阻止 XSS 操作用户账号。

  • 401 与 403 的基本区别。

  • permitAll() 不等于跳过整个安全过滤器链。

相关推荐
Java成神之路-3 天前
浏览器同源策略与 CORS 跨域详解
cors
样子20184 天前
Js 之根据白名单过滤 HTML(防止 XSS 攻击)
android·前端·javascript·html·xss
DsirNg4 天前
登录后的那一个小时:把前端会话续期做成可收敛的控制面
xss·csrf·token·cookie·refresh token·前端安全·登录态
小江的记录本15 天前
【CSS】CSS 核心:盒模型、BFC/IFC、Flex/Grid 布局、响应式布局、移动端适配(附《思维导图》)
前端·css·面试·前端框架·tensorflow·html5·xss
DsirNg15 天前
凭证不是登录态:从攻击面重做浏览器认证设计
oauth·xss·csrf·token·cookie·认证授权·web 安全
蒲公英eric17 天前
从客户端到服务端:DVWA DOM 型 XSS 模块完整漏洞分析教程
前端·web安全·ai·xss·dvwa·ai安全
Blockchina18 天前
Codex安全盲区:我用4组本地测试复盘SQLi、XSS、越权与路径穿越
sql·安全·xss
黄俊懿18 天前
【架构师从入门到进阶】第五章:DNS&CDN&网关优化思路——第七节:网关-XSS攻击与预防
网关·网络安全·架构·系统架构·架构师·xss·架构设计
HackTwoHub19 天前
Butter_Cookie 黄油曲奇|浏览器渗透插件,云存储检测、XSS、SQL 注入一站式 Web 安全测试工具
前端·sql·安全·web安全·网络安全·自动化·xss