前端编码如何防XSS

wen 开源项目 29

本文目录导读:

前端编码如何防XSS

  1. 核心原则:上下文输出编码
  2. 现代框架的正确使用(推荐)
  3. 特殊场景的预防措施
  4. 其他关键防御点
  5. 总结:前端防 XSS 检查清单

前端防范 XSS(跨站脚本攻击)的核心原则是:永远不要信任用户输入,对所有输出进行编码

就是当用户输入的数据作为HTML内容、属性、JavaScript代码或URL插入到页面时,必须将其转换为安全的、无执行能力的字符串。

以下是前端编码中具体的防XSS措施,按优先级排列:

核心原则:上下文输出编码

XSS发生的根本原因是数据被当成了代码执行,你需要根据数据将要出现的“上下文”使用不同的编码方式,不能简单地只做一次 htmlspecialcharsescape

上下文 说明 编码方法 示例
HTML 标签内容 数据放在 <div>...</div> 之间 HTML实体编码
& -> &amp;
< -> &lt;
> -> &gt;
-> &quot;
-> &#x27;
用户输入: <script>alert(1)</script>
编码后: &lt;script&gt;alert(1)&lt;/script&gt;
HTML 属性 数据放在 <input value="..."> HTML属性编码
除上述外,需特别注意对引号和空格编码。
用户输入: " autofocus onfocus="alert(1)
编码后: &quot; autofocus onfocus=&quot;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-htmldangerouslySetInnerHTMLinnerHTML,如果必须使用富文本编辑器,请使用经过严格安全过滤的库。

特殊场景的预防措施

A. 富文本 / Markdown 渲染

如果你允许用户输入 HTML 标签(如文章编辑器、评论区),绝不能直接渲染。

  • 第一步:白名单过滤。 只允许安全的标签(<b> <i> <a> <img> 等)和属性(href src alt 等)。
  • 第二步:使用可靠库。 使用成熟库进行处理,不要手写正则。
    • 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 检查清单

  1. 框架默认编码:是否依赖框架的 或 插值?
  2. 禁止危险 API:是否使用了 innerHTMLdocument.writev-html
  3. 富文本过滤:是否使用了 DOMPurify 等库来清理富文本?
  4. URL 校验:处理 hrefsrc 时,是否过滤了 javascript: 协议?
  5. CSP 策略:是否配置了严格的 script-srcobject-src
  6. 第三方库:使用的第三方库(如 Highcharts、Markdown 解析器)是否已更新到无已知 XSS 漏洞的版本?

一句话法则:

不要相信任何来自用户(或 URL、数据库、API)的数据,在它进入 HTML 标签、属性、JS 字符串、URL 或 CSS 中的 '引号' 之前,必须进行对应的编码处理。

抱歉,评论功能暂时关闭!