本章目录(8)On this page (8)
  1. 成立条件只有一个
  2. 先找位置,再想 payload
  3. 容易被忽略的输入点
  4. 一个真实的绕过过程
  5. 编码顺序决定能不能绕
  6. 危害取决于上下文
  7. 修复
  8. 参考
文章Articles

XSS

出现位置、测试顺序、编码绕过,以及「弹框」和「真的能用」之间的距离。

更新Updated 2026.10.25securitywebxss

成立条件只有一个

用户输入被输出到页面上,且没做正确的转义。

所有的变体都是这条的变形:反射型是输出在响应里,存储型是输出在数据库里,DOM 型是输出在前端脚本里、根本不经过服务端。

先找位置,再想 payload

新手常犯的错是背了一堆 payload,到处试,试不出来就放弃。顺序反了。

正确的顺序是:先输入几个特殊字符("'<>),看它们出现在页面的哪个位置、周围是什么、有没有被转义。

位置决定 payload:

  • 出现在 HTML 标签之间 → 直接构造标签
  • 出现在属性值里(value="xxx")→ 先闭合引号,再闭合标签
  • 出现在 <script> 里 → 不用标签,直接构造 JS 语句
  • 出现在 href、src、action 里 → 试伪协议 javascript:

这几条判断,比记住二十个 payload 有用。

容易被忽略的输入点

能输入的地方都可能有,但有几类特别值得看:

富文本编辑器。公告、邮件正文、工单描述、评论。编辑器允许的标签集合往往很宽,而存储时不做二次过滤。这类功能出问题的比例,比其他输入点高得多。

上传的文件名。上传一个叫 <img src=1 onerror=alert(1)>.png 的文件,如果列表页直接输出文件名而不转义,就成立了。

文件内容本身。允许传 PDF、SVG、HTML 的地方,文件打开就是在浏览器里渲染。SVG 里可以直接写 script。

邮件。内部邮件系统的正文、主题、发件人名。这类系统经常忘了自己也是个 Web 应用。

一个真实的绕过过程

某个后台的反馈功能,输入 payload 直接 404,说明有过滤。

挨个字符试,发现尖括号被拦。换 Unicode 编码 \u003c,不拦,但前端不解析——服务端没做那一步解码。

转去试标题字段。标题在列表页输出时,右键看 HTML,尖括号没转义,但引号位置有闭合问题。先打一个双引号,输出也没处理。

到这里就清楚了:这个字段处在属性上下文里,且不转义引号。最终构造:

\"\u003cinput/onfocus=_=confirm,_(123)\u003e

\u003c 被服务端解码成 <,input 标签带 onfocus 自动聚焦触发,alert 被过滤就用 confirm,括号被干扰就用 _ 当临时变量。四个绕过点叠在一起,才打进去。

这个过程没什么技巧,就是把「哪里被拦」一个个试出来。写出来是为了说明:绕过不是一个 payload,是一串判断。

编码顺序决定能不能绕

浏览器解码的顺序是固定的:

HTML 解码 → URL 解码 → JavaScript 解码

服务端过滤和浏览器解码的顺序不一致,就是绕过的空间。这条是理解所有编码绕过的根。

几个常用的替换:

被拦 换成
alert confirm、prompt、console.log
空格 /**/、换行、%0a
引号 反引号、String.fromCharCode
括号 反引号模板、throw onerror=...
尖括号 Unicode、HTML 实体(需服务端先解码)

alert 的变形可以写得很花:top['al'+'ert'](1)、[].find(alert)、(alert)(1)。目的只有一个——让过滤规则匹配不到,让 JS 引擎认得。

危害取决于上下文

弹框是最低级的证明,报告里写「存在 XSS,可弹框」基本等于没说。

往下走一步:能读到什么?document.cookie 有没有 HttpOnly?能不能发起同源请求?能不能读页面里的敏感数据?

存储型 XSS 如果出现在后台,且管理员会看到,那就是「管理员会话劫持」。如果出现在用户之间互相可见的地方,那就是「蠕虫」的起点。这两种定级完全不同。

修复

四条,按优先级:

  1. 输出时按上下文转义。HTML 上下文转 < > & " ',属性上下文还要处理引号,JS 上下文用 JSON.stringify。不要试图在输入时过滤——输入时的过滤永远有遗漏。
  2. 富文本用白名单。允许哪些标签、哪些属性,写死。黑名单一定会漏。
  3. Cookie 加 HttpOnly。降低被劫持的后果,不解决漏洞本身。
  4. CSP。最后一道,配置正确能挡住大部分。但很多站点的 CSP 写得很宽,unsafe-inline 一开就等于没有。

参考

  • 《XSS 测试利用总结(附个人常用 payload)》,公众号 起凡安全
  • 《XSS 攻击在新花样》,公众号存档
  • 《几个有趣的 bypass 挖洞案例》,公众号 渗透安全HackTwo