XSS 攻防全解:反射型、存储型、DOM 型实战演示

文章目录

    • [一、先建立正确心智:XSS 伤的是谁](#一、先建立正确心智:XSS 伤的是谁)
    • [二、三类 XSS:一张表建立直觉](#二、三类 XSS:一张表建立直觉)
    • [三、反射型 XSS:实战演示思路](#三、反射型 XSS:实战演示思路)
      • [1. 它长什么样](#1. 它长什么样)
      • [2. 演示路径(请在靶场做)](#2. 演示路径(请在靶场做))
      • [3. 位置比 payload 重要](#3. 位置比 payload 重要)
      • [4. 反射型的修复直觉](#4. 反射型的修复直觉)
    • [四、存储型 XSS:实战演示思路](#四、存储型 XSS:实战演示思路)
      • [1. 它为什么更凶](#1. 它为什么更凶)
      • [2. 演示路径(靶场)](#2. 演示路径(靶场))
      • [3. 富文本:存储型的重灾区](#3. 富文本:存储型的重灾区)
      • [4. 存储型修复直觉](#4. 存储型修复直觉)
    • [五、DOM 型 XSS:实战演示思路](#五、DOM 型 XSS:实战演示思路)
      • [1. 为什么说"服务端可能是清白的"](#1. 为什么说“服务端可能是清白的”)
      • [2. 演示路径(自建一小页即可)](#2. 演示路径(自建一小页即可))
      • [3. 现代前端里的变体](#3. 现代前端里的变体)
      • [4. DOM 型修复直觉](#4. DOM 型修复直觉)
    • 六、串起来的一条"实战演示"主线(适合内训)
    • [七、测试方法论(比收藏 payload 重要)](#七、测试方法论(比收藏 payload 重要))
      • [1. 找入口](#1. 找入口)
      • [2. 探针优先](#2. 探针优先)
      • [3. 看上下文再构造](#3. 看上下文再构造)
      • [4. 双浏览器 / 双账号](#4. 双浏览器 / 双账号)
      • [5. 自动化辅助,人工收口](#5. 自动化辅助,人工收口)
    • 八、防御全解:分层才像会打仗
      • [1. 输出编码(第一原则)](#1. 输出编码(第一原则))
      • [2. 输入校验(辅助)](#2. 输入校验(辅助))
      • [3. 富文本清理](#3. 富文本清理)
      • [4. Cookie:HttpOnly、Secure、SameSite](#4. Cookie:HttpOnly、Secure、SameSite)
      • [5. CSP(Content Security Policy)](#5. CSP(Content Security Policy))
      • [6. 框架与危险 API 纪律](#6. 框架与危险 API 纪律)
      • [7. 安全头与其它](#7. 安全头与其它)
    • [九、和 OWASP Top 10 的关系](#九、和 OWASP Top 10 的关系)
    • 十、常见误区
    • 十一、收尾

XSS(Cross-Site Scripting,跨站脚本)听起来像某种高深的"跨站黑科技",真落到业务里,多半是一句很土的话:

页面把用户可控的内容,当成了脚本执行了。

可能是搜索框把关键字原样写回 HTML;可能是评论区存了一段 <script>,谁打开谁中招;也可能是前端用 innerHTML 拼了个 URL 参数,压根没经过服务端。三种常见面孔------反射型、存储型、DOM 型------本质同一类病:不可信数据进了浏览器的"代码语境"。

另外说句实在话:现在 HttpOnly、框架自动转义、CSP 越来越普及,有人宣布 XSS 已死。然后每年还能在重要系统里看见评论区、富文本、运营配置后台、老 jQuery 页面中招。死的是"无脑 <script>alert(1)",不是整个问题域。


一、先建立正确心智:XSS 伤的是谁

SQL 注入主要伤服务器和数据;XSS 主要伤正在用浏览器的人

脚本跑在受害者浏览器里,能做的事情取决于页面所处的源(origin)和页面能力,常见包括:

  • 偷当前站可用的数据(若 Cookie 非 HttpOnly,可能读到会话 Cookie;HttpOnly 则改走其它路);
  • 以受害者身份发请求(改邮箱、转账、发帖),也就是挂着用户会话的 CSRF 式操作;
  • 钓鱼:在真域名下画假登录框;
  • 配合其它洞做跳板。

所以评估 XSS 时,别停在 alert(1)alert 只是证明"我能执行脚本"。真正的问题是:在谁的浏览器里、以谁的身份、能碰到什么功能。


二、三类 XSS:一张表建立直觉

类型 脚本从哪来 典型触发 测试时盯什么
反射型 当前请求参数被立刻写进页面 点开带毒链接 URL/表单参数是否进 HTML
存储型 先存进服务器,以后每次打开都带出来 看帖、看消息、看后台 存储内容再展示的路径
DOM 型 主要在前端 JS 里改 DOM 改 hash/参数即可 innerHTMLeval、危险 sink

一句话区分:

  • 反射:请求里来,响应里走,多半不进库;
  • 存储:进库(或进能持久的地方),别人也会中;
  • DOM:服务端可能完全干净,锅在前端。

三、反射型 XSS:实战演示思路

1. 它长什么样

最典型:搜索页。

你搜 hello,页面显示"您搜索的是:hello"。若后端或模板把关键字不经编码塞进 HTML,把关键字换成可执行的 HTML/JS,浏览器就会执行。

受害者通常需要打开攻击者构造好的链接(或被钓鱼点开)。所以反射型常和社工、短链、广告投放一起出现。

2. 演示路径(请在靶场做)

环境: DVWA 反射型关卡,或自己写一个"回显参数"的页面。

步骤大致是:

  1. 找一个参数,它的值会出现在响应 HTML 里;
  2. 先提交一个无害标记,例如 xss_probe_12345,确认它原样出现在哪里(标题、属性、正文、脚本块里位置不同,手法不同);
  3. 根据位置尝试能否形成可执行上下文------例如是否进了标签体、是否进了属性、是否进了 JavaScript 字符串;
  4. 用最简单的执行证明(教学上常用弹窗)证明脚本执行;
  5. 再讨论:若 Cookie 无 HttpOnly 会怎样(演示到"能读到什么"为止,别对外打真实账号)。

3. 位置比 payload 重要

同样是"注入字符串",落点不同难度差很多:

  • 落在 HTML 文本节点:常要形成标签;
  • 落在属性值:要考虑引号闭合、事件属性;
  • 落在已有 <script> 字符串里:要考虑引号与编码;
  • 落在 URL 属性:可能变成 javascript: 协议问题。

老手第一件事不是砸字典,是看回显点源码上下文。Chrome F12 比一百条盲打有用。

4. 反射型的修复直觉

模板引擎默认转义;输出到 HTML 用对应编码;能用纯文本就别用"可解析 HTML"。

业务若必须允许链接,用白名单标签的清理库,别自己写正则"过滤 script"。


四、存储型 XSS:实战演示思路

1. 它为什么更凶

脚本躺在服务器上(评论、文章、用户简介、工单回复、后台配置)。受害者只要正常浏览,就可能中招------不一定非要点奇怪链接。管理员一打开"用户反馈",管理会话就可能交代。

所以存储型在危害评级里通常高于同类反射型:影响面是"谁会看到这条数据"。

2. 演示路径(靶场)

  1. 找会保存并再展示的功能:留言板最经典;
  2. 提交探针字符串,保存后打开详情页,看是否原样进 HTML;
  3. 换成可执行证明,用另一个浏览器配置/另一个账号打开,确认"存储后触发";
  4. 观察触发角色:普通用户互看?还是仅管理员后台预览?角色决定危害。

3. 富文本:存储型的重灾区

产品经理常说:"评论要支持加粗和图片。"

于是上线富文本编辑器,服务端若只做半吊子过滤,攻击者就能塞事件属性、畸形标签、svg onload 之类。

这里有个残酷事实:自己写 HTML 过滤器几乎必输。 用成熟的、默认安全的清理库(并保持更新),白名单标签与属性,去掉事件处理器和危险协议。

4. 存储型修复直觉

  • 存可以存原文,出必须按上下文编码;或
  • 存之前就清理成安全子集;
  • 管理端预览也要走同一套安全输出,别"后台信任自己人"。

五、DOM 型 XSS:实战演示思路

1. 为什么说"服务端可能是清白的"

DOM XSS 的数据流主要在浏览器里:

text 复制代码
源(source):location、hash、referrer、postMessage...
      ↓  前端 JS 处理
汇(sink):innerHTML、document.write、eval、$('...').html()...

服务端返回的 HTML 可能完全固定;脚本执行是前端自己用不可信数据去喂了危险 API。

传统只抓包看响应的测试,会漏掉 DOM XSS。要用浏览器调试,看参数进了哪段 JS。

2. 演示路径(自建一小页即可)

很多教程会写一个糟糕页面:从 location.hash 取字符串,赋给 innerHTML。你改 URL 的 # 后面内容,页面就会执行。

练习时建议你亲自写坏再修好:

  1. 先复现危险写法;
  2. 改成 textContent 或明确创建文本节点;
  3. 若必须插 HTML,用经过清理的结果,并考虑 CSP。

3. 现代前端里的变体

  • 前端路由把 query 写进页面;
  • postMessage 没验 origin;
  • localStorage 读出以前存的脏数据再 innerHTML
  • 第三方小部件配置项进 DOM。

SPA 流行后,DOM XSS 的占比其实上升了------只是名字不总叫"跨站",而叫"前端漏洞"。

4. DOM 型修复直觉

危险 sink 清单贴在团队 Wiki:禁止对不可信数据用 innerHTML / document.write / 拼 on* 属性。

React 默认文本转义有帮助,但 dangerouslySetInnerHTML 就是明示危险;Vue 的 v-html 同理。用之前问:数据从哪来?


六、串起来的一条"实战演示"主线(适合内训)

如果你要做一场两小时内部演示,我建议别三类各打一遍字典,而是讲一个故事:

场景: 一个带搜索、评论、前端高亮关键词的小站点。

  1. 反射: 搜索关键词回显 → 证明反射型;
  2. 存储: 评论保存恶意内容 → 另一账号打开帖子中招;
  3. DOM: 前端用 URL 参数高亮关键词,却 innerHTML → 服务端已转义仍中招。

同一业务三种洞,学员一下就懂"输出编码要按场景做,前端也是战场"。

演示结束一定留 15 分钟讲修复提交:模板转义、评论清理、前端改 textContent、加一层 CSP。否则演示就是表演玩火。


七、测试方法论(比收藏 payload 重要)

1. 找入口

所有用户可控且可能被展示的地方:参数、表单、上传文件名、头像 URL、回调地址、邮件模板、运营配置。

别忽略"只有管理员能看的数据"------那经常是存储型高危。

2. 探针优先

先用独一无二的字符串确认数据流,再谈执行。

乱砸 payload 会被 WAF 干扰,你也分不清是没回去还是被过滤。

3. 看上下文再构造

进 HTML、属性、JS、CSS、URL,编码方式不同。

"万能 payload"是幻觉;上下文才是地图。

4. 双浏览器 / 双账号

存储型必须验证"他人视角"。反射型验证"换个未登录/另一用户点链接"。

5. 自动化辅助,人工收口

爬虫式 XSS 扫描器能找简单反射;DOM 与业务型存储仍靠人。扫出来的东西要人工确认,减少把标签过滤误报当战果。


八、防御全解:分层才像会打仗

1. 输出编码(第一原则)

数据离开信任边界、进入 HTML/属性/JS 时,做对应上下文 的编码。

在现代框架里,优先用默认转义的模板绑定,少拼原始 HTML。

2. 输入校验(辅助)

长度、格式、白名单字符------能减少垃圾,不能当唯一防线。攻击者编码花样太多。

3. 富文本清理

成熟库 + 白名单;升级跟依赖 SLA 走。

允许的标签里不要留事件属性;URL 只允许 http(s)。

4. Cookie:HttpOnly、Secure、SameSite

HttpOnly 让 JS 读不到会话 Cookie,能挡一类偷票;不挡以用户身份发请求的那类攻击,所以还要配合 CSRF 防护与敏感操作二次确认。

5. CSP(Content Security Policy)

CSP 像给浏览器下"脚本纪律":默认禁止乱七八糟的内联脚本与陌生域脚本时,XSS 成功率会断崖下降。

落地难在兼容:要先 Report-Only 观察,再 enforce;尽量配合非ce 降低绕过。别指望一天全站完美 CSP,但关键登录域值得先做。

6. 框架与危险 API 纪律

禁止清单比鼓励清单好使:Code Review 扫 dangerouslySetInnerHTMLv-htmlinnerHTML=

发现一处,问数据源。

7. 安全头与其它

X-Content-Type-Options: nosniff 等减少浏览器猜类型带来的意外。

完整安全头方案可另开一篇;这里只强调:XSS 不是只靠一个头解决。


九、和 OWASP Top 10 的关系

XSS 在旧版 Top 10 里单列多年,2021 起更多并入注入/其它类别的讨论,但业务上它仍独立存在。

和 A01 越权常联动:先 XSS 管理员,再改配置;和 A07 认证失败也联动:伪造登录框收口令。

修 XSS 时顺手看敏感操作有没有二次验证,性价比很高。


十、常见误区

"我们过滤了 script 关键字。"

大小写、编码、标签变形、事件属性、SVG,正则防 XSS 历史记录不太光彩。

"框架默认防 XSS,所以没事。"

直到有人用了危险 API,或把用户 HTML 当可信。

"有 WAF。"

WAF 挡一部分反射;存储与 DOM 经常绕开它的舒适区。

"HttpOnly 了,XSS 没用。"

攻击者仍可以让浏览器自己去点"删除账号""导出数据"。

"内部系统不需要防 XSS。"

内部系统才常有高权限用户,存储型更值钱。


十一、收尾

反射型像钓鱼链接上的一次性炮弹;

存储型像埋在业务数据里的地雷;

DOM 型像前端自己挖的坑,服务端查岗都可能查不到。

攻的一方(授权测试)要会看上下文、会追数据流、会换角色验证;

防的一方要把输出编码、富文本纪律、危险 sink、CSP、Cookie 属性做成默认,而不是出了事再救火。

今晚若只做一件事:打开你们站点一个"用户输入会显示出来"的页面,在测试环境提交一个独一无二的探针字符串,然后 View Source 看它落在谁家里------标签体、属性,还是进了某段前端模板。

认清落点之后,你对 XSS 的理解会比背十个弹窗字符串扎实得多。

三类演示都走通以后,你会发现所谓"全解"其实不神秘:

数据在哪里变成了代码,就在哪里设防。


相关推荐
Richard.Wong1 小时前
Windows IIS 服务器部署 Vue3 前端项目详细流程
服务器·前端·windows
Nemo_XP1 小时前
C# gridlookupedit选中内容重复还原操作
服务器·前端·c#
大家的林语冰1 小时前
🎉 Vercel 官宣 Next 16.3 正式发布,GitHub 第一全栈框架再次进化!
前端·javascript·前端框架
阿凉07021 小时前
STO安全扭矩关断接线
安全
不爱说话郭德纲2 小时前
我只给了 TRAE Work 一张差评截图,它最后却把自己的 P0 结论推翻了?
前端·后端·架构
hoaxxcj2 小时前
多智能体把云可靠性工程自动化:NeurIPS 2025 的 STRATUS 比 SOTA 强 1.5 倍,还顺手定了条“安全规范“
运维·安全·自动化·大模型·ai论文·前沿解读
用户938515635072 小时前
从 DOM 编程到声明式 UI:React useRef 与 useState 底层全解析
前端·javascript·react.js
kisshyshy2 小时前
前端路由进化史:从刷新白屏到SPA,手写一个Hash路由就懂了!
前端·javascript·react.js
KKKlucifer3 小时前
AI 驱动告警研判:运营商智能化安全运维支撑服务实践案例
人工智能·安全