XSS 原理与防御

从脚本执行、上下文差异、存储型/反射型/DOM型 XSS 开始理解 XSS 原理,并总结输出编码、CSP、HttpOnly、SameSite 等防御方法。

写在前面:合法学习边界

本文讲解 XSS 的原理与防御。所有示例只用于理解漏洞触发机制,不能直接用于真实网站攻击。任何 XSS 测试都必须在自建靶场、公司授权测试环境或明确书面授权的目标上进行。未经授权窃取 Cookie、劫持会话、执行脚本或读取用户数据,可能违反《网络安全法》《数据安全法》《个人信息保护法》和《刑法》相关规定。

一、XSS 的本质

XSS(跨站脚本攻击)的本质是:浏览器把攻击者提供的输入当成可执行 JavaScript 执行了。

它利用的是浏览器的信任机制:

1
2
3
网页内容由服务器返回
脚本来自网页自身
浏览器默认信任同域脚本

如果后端或前端把用户输入直接插入页面,且没有正确处理上下文,攻击者就可能把一段脚本塞进页面中。

二、XSS 的常见类型

1. 存储型 XSS

恶意脚本被保存到服务器,例如评论、个人资料、商品描述、上传文件名。后续访问者打开页面时都会执行脚本。

存储型 XSS 危害通常更大,因为影响范围更广。

2. 反射型 XSS

恶意脚本通过 URL 参数、搜索框、表单回显进入页面,不会保存下来,但特定链接被打开时可能执行。

反射型 XSS 常用于钓鱼和会话劫持。

3. DOM 型 XSS

恶意脚本发生在浏览器端。页面 JS 把某个 DOM 值写入 innerHTMLdocument.write 或事件属性,浏览器执行了其中的脚本。

DOM 型 XSS 常见于:

1
2
3
4
URL hash 处理
前端路由参数
搜索框回显
富文本编辑器

三、为什么“编码”是关键

XSS 不是简单的“有 <script> 就危险”。危险来自“上下文”。

不同上下文的编码规则不同:

1
2
3
4
5
HTML 文本上下文
HTML 属性上下文
JavaScript 字符串上下文
URL 上下文
CSS 上下文

正确防御是:

1
2
3
在输出时按上下文编码
不要盲目信任前端框架
不要把所有输出都当成安全

四、常见危险点

1. innerHTML

1
element.innerHTML = userInput

如果 userInput 中包含 <img onerror="...">,浏览器可能执行脚本。

2. document.write

旧式脚本中常见:

1
document.write(userInput)

这种写法容易破坏页面安全边界。

3. 事件属性

1
<img src=x onerror="alert(1)">

事件属性是常见触发点。

4. URL 跳转

某些旧系统会把用户输入直接放入 hreflocation.href。如果上下文没处理好,也可能成为 XSS 入口。

影响与危害

XSS 能造成:

1
2
3
4
窃取 Cookie/会话(账号被劫持)
钓鱼与页面篡改
键盘记录
配合 CSRF 执行恶意操作

存储型 XSS 影响所有访问该页面的用户。风险等级:中到高。

五、防御方法

1. 输出编码

按上下文进行输出编码,是 XSS 防御的核心。

2. 输入校验

输入校验可以减少风险,但不应作为唯一防线。它更多是业务层保护。

3. 安全的 DOM API

避免直接写入 HTML,优先使用文本安全 API。

4. CSP

内容安全策略(CSP)可以限制脚本来源,降低 XSS 影响。

给敏感 Cookie 设置:

1
2
3
HttpOnly
Secure
SameSite

即使脚本执行,也不要让它轻易拿到 Cookie。

6. 最小权限和最小暴露

后台、评论、个人资料、富文本编辑器都要做专门审查。

修复

1
2
3
4
5
输出编码(上下文敏感:HTML/属性/JS 分别编码)
输入白名单校验
设置 CSP 降低执行面
HttpOnly 防 Cookie 被窃取
修复后复测:注入 payload 不再被执行

六、XSS 在报告中的正确写法

好的报告要写出触发条件、影响和建议。

示例:

1
2
3
发现:评论区输入 <img src=x onerror="alert(1)"> 会在其他用户页面执行脚本。
风险:可能造成会话劫持、钓鱼、数据读取和页面篡改。
建议:输出编码;启用 CSP;限制富文本标签;敏感 Cookie 设置 HttpOnly、Secure、SameSite。

不要只写“存在 XSS”。要写清楚触发路径和影响。

七、小结

XSS 的核心不是“能不能注入标签”,而是“浏览器在哪个上下文执行了这段输入”。理解上下文,才能同时理解防御和绕过。后续学习 CSRF、SSRF、WAF 和日志分析时,都会回到 XSS 的上下文思维。