本文目录导读:

前端防范 XSS(跨站脚本攻击)的核心原则是:永远不要信任用户输入,对所有输出进行编码。
就是当用户输入的数据作为HTML内容、属性、JavaScript代码或URL插入到页面时,必须将其转换为安全的、无执行能力的字符串。
以下是前端编码中具体的防XSS措施,按优先级排列:
核心原则:上下文输出编码
XSS发生的根本原因是数据被当成了代码执行,你需要根据数据将要出现的“上下文”使用不同的编码方式,不能简单地只做一次 htmlspecialchars 或 escape。
| 上下文 | 说明 | 编码方法 | 示例 |
|---|---|---|---|
| HTML 标签内容 | 数据放在 <div>...</div> 之间 |
HTML实体编码 & -> & < -> < > -> > -> " -> ' |
用户输入: <script>alert(1)</script> 编码后: <script>alert(1)</script> |
| HTML 属性 | 数据放在 <input value="..."> 中 |
HTML属性编码 除上述外,需特别注意对引号和空格编码。 |
用户输入: " autofocus onfocus="alert(1) 编码后: " autofocus onfocus="alert(1) |
| JavaScript 字符串 | 数据放在 <script> var x = '...'; </script> 中 |
JavaScript 字符串编码 将 \n \r 等转义为 Unicode 或 Hex 形式。 |
用户输入: '; alert(1);// 编码后: \x27; alert(1);// |
| URL 参数 | 数据放在 href="...?redirect=..." 中 |
URL 编码 encodeURIComponent() |
用户输入: javascript:alert(1) 编码后: javascript%3Aalert(1) |
现代框架的正确使用(推荐)
这是目前最有效的方法,现代前端框架(React、Vue、Angular、Svelte)在默认情况下会自动对绑定的数据进行编码,除非你刻意跳过。
- React:
- 安全: 使用
{userInput},React 在渲染前会自动进行 HTML 实体编码。 - 危险: 使用
dangerouslySetInnerHTML={{ __html: userInput }}。
- 安全: 使用
- Vue:
- 安全: 使用
{{ userInput }},Vue 会自动进行文本插值转义。 - 危险: 使用
v-html="userInput"。
- 安全: 使用
- Angular:
- 安全: 使用
[innerText]="userInput"或{{ userInput }}。 - 危险: 使用
[innerHTML]="userInput"。
- 安全: 使用
黄金法则: 尽量不要使用 v-html、dangerouslySetInnerHTML 或 innerHTML,如果必须使用富文本编辑器,请使用经过严格安全过滤的库。
特殊场景的预防措施
A. 富文本 / Markdown 渲染
如果你允许用户输入 HTML 标签(如文章编辑器、评论区),绝不能直接渲染。
- 第一步:白名单过滤。 只允许安全的标签(
<b><i><a><img>等)和属性(hrefsrcalt等)。 - 第二步:使用可靠库。 使用成熟库进行处理,不要手写正则。
- DOMPurify(最推荐): 专门用来清理 HTML,非常强大且高速,它可以与任何框架(React、Vue、jQuery)配合使用。
- sanitize-html: Node.js 端和客户端均可使用。
- js-xss(xss.js): 另一个流行的过滤库。
示例(DOMPurify):
import DOMPurify from 'dompurify'; let cleanHTML = DOMPurify.sanitize(userInputHTML); // 然后将 cleanHTML 赋值给 innerHTML 或 v-html
B. URL 处理(防止 javascript: 伪协议)
用户通常可以输入链接,需要防范 javascript:alert(1) 这种链接。
function sanitizeUrl(url) {
// 禁止以 javascript: data: (非图片类型) vbscript: 开头
if (/^(javascript|data|vbscript):/i.test(url)) {
return 'about:blank'; // 或抛出错误
}
try {
new URL(url); // 进一步验证 URL 格式
return url;
} catch {
return 'about:blank';
}
}
C. CSS(style 属性)
尽量避免允许用户直接修改 style 属性,如果必须,需要对值进行校验(限制为颜色、字体大小等基本属性),并禁止使用 expression() 或 url(javascript:...)。
其他关键防御点
A. 设置 Cookie 的 HttpOnly 属性(后端配合)
虽然这是后端的责任,但前端开发者需要知道:重要敏感信息(如 Session ID)不应该被 JavaScript 访问。
Set-Cookie: sessionid=xxx; HttpOnly; Secure; SameSite=Strict
这样即使 XSS 发生,攻击者也拿不到你的 Cookie。
B. 内容安全策略(CSP,Content Security Policy)
这是浏览器层面的最后一道防线,通过 HTTP 头或 <meta> 标签来限制页面可以加载和执行的资源。
- 限制脚本来源: 只允许执行本站或白名单 CDN 的脚本。
Content-Security-Policy: script-src 'self' 'nonce-random123' - 禁止内联脚本: 防止攻击者注入
<script>alert(1)</script>。Content-Security-Policy: script-src 'self' - 禁止
eval(): 禁用eval()、setTimeout(string)等危险函数。Content-Security-Policy: script-src 'self' 'unsafe-inline'(不推荐unsafe-inline)
C. 避免 eval() 系列函数
避免使用 eval()、new Function()、setTimeout(string)、setInterval(string),这些函数会将字符串当作代码执行,是 XSS 攻击的常见入口。
前端防 XSS 检查清单
- 框架默认编码:是否依赖框架的 或 插值?
- 禁止危险 API:是否使用了
innerHTML、document.write、v-html? - 富文本过滤:是否使用了
DOMPurify等库来清理富文本? - URL 校验:处理
href或src时,是否过滤了javascript:协议? - CSP 策略:是否配置了严格的
script-src和object-src? - 第三方库:使用的第三方库(如 Highcharts、Markdown 解析器)是否已更新到无已知 XSS 漏洞的版本?
一句话法则:
不要相信任何来自用户(或 URL、数据库、API)的数据,在它进入 HTML 标签、属性、JS 字符串、URL 或 CSS 中的 '引号' 之前,必须进行对应的编码处理。