介绍
在网络安全中,跨站脚本 (XSS) 是最古老、最持久的漏洞之一。
如果恶意脚本在受害者的浏览器上运行,它们可能会破坏整个会话、窃取会话令牌 (cookie)、劫持帐户或动态更改页面内容以获取敏感凭据。
本文回顾了消除现代 Web 应用程序中 XSS 漏洞所需的基本防御原则。我们将探索上下文转义、清理、安全 DOM 操作和防御深度机制。
1.XSS的三种分类
根据恶意负载的传输方式,XSS 漏洞大致分为三类:
- 反射的XSS: 当恶意负载嵌入到链接或表单提交中时会发生。当用户单击链接时,服务器会将不受信任的输入“反射”回响应 HTML,而无需进行适当的转义。
- 存储(持久)XSS: 最危险的形式。有效负载存储在服务器的数据库中(例如,论坛帖子、用户简介)并传递给访问该页面的任何后续用户。
- 基于 DOM 的 XSS:
与反射或存储 XSS 不同,这完全发生在客户端 JavaScript 中。该脚本处理不受信任的源数据(例如
location.hash或查询参数)并使用不安全的 API 将其直接写入 DOM。
2. 原则 1:上下文感知 HTML 转义
XSS 的根本解决方法是在渲染不受信任的动态数据之前对其进行转义。转义将 HTML 语法中具有特殊含义的字符文字转换为各自的惰性 HTML 实体(字符引用)。
基本字符映射表
&->&<-><>->>"->"'->'(或')
警告:上下文很重要
转义规则根据数据放置的“位置”而变化。
- 放置在元素标记内的文本需要标准实体转义。
- 放置在元素属性内的文本(例如
<input value="DYNAMIC_DATA">)需要严格的引号转义。 - 单独使用 HTML 转义无法保护
<script>块、CSS 布局或 URL 属性 (href) 内呈现的数据。它们分别需要 JavaScript 转义、CSS 转义或 URL 编码。
3. 原则 2:安全 DOM API(防止基于 DOM 的 XSS)
使用 JavaScript 动态更新页面内容时,选择错误的 API 可能会造成安全漏洞。
不良做法
// Reading a query parameter and injecting it directly
const params = new URLSearchParams(window.location.search);
const username = params.get("name");
// DANGEROUS: If name is "<img src=x onerror=alert(1)>", the script will execute
document.getElementById("greeting").innerHTML = `Hello, ${username}!`;
最佳实践
如果要将动态数据解释为纯文本,请始终使用 textContent 或 innerText 而不是 innerHTML。
const params = new URLSearchParams(window.location.search);
const username = params.get("name");
// SAFE: The browser treats input strictly as plain text, rendering tags harmlessly
document.getElementById("greeting").textContent = `Hello, ${username}!`;
如果您的应用程序必须呈现用户提供的 HTML 标记(例如,Markdown 预览),则必须首先将字符串传递给经过考验的清理库(例如 DOMPurify)。
4. 原则 3:安全链接方案
当应用程序允许用户保存网站链接并直接在锚元素 (<a href="USER_URL">) 中呈现它们时,就会出现常见的安全漏洞。
风险
即使您转义 HTML 字符,用户也可以提供类似 javascript:alert(document.cookie) 的有效负载。单击该链接将立即执行该脚本。
<!-- DANGEROUS: The script executes when clicked -->
<a href="javascript:alert(document.cookie)">Visit Website</a>
解决方案
对用户 URL 实施严格的方案验证。仅允许显式以 http:// 或 https:// 开头的 URL,拒绝 javascript: 或 data: 等方案。
5.纵深防御
仅仅依靠代码清理是有风险的。分层浏览器安全控制提供了一个重要的安全网。
内容安全策略 (CSP)
内容安全策略是一个 HTTP 响应标头,它定义允许哪些脚本源在您的页面上运行。
Content-Security-Policy: default-src 'self'; script-src 'self' https://trustedscripts.com;
强大的 CSP 可以限制内联脚本,即使存在逃逸漏洞,也可以防止注入的有效负载运行。
仅 Http Cookie
通过 cookie 发出会话标识符时,请始终设置 HttpOnly 标志。这可以防止客户端脚本读取 cookie 值(通过 document.cookie),从而减少会话盗窃,即使 XSS 攻击成功也是如此。
结论
保护您的 Web 应用程序免受 XSS 侵害需要一致性:
- 将上下文感知转义应用于所有动态输入。
- 对于 DOM 操作,优先使用
textContent而不是innerHTML。 - 在渲染链接之前验证 URL 方案 (
http:/https:)。 - 使用内容安全策略和 HttpOnly cookie 作为安全网。
通过将这些安全实践纳入您的开发工作流程,您可以防止 XSS 漏洞。

