XSS跨站脚本攻击如何有效过滤

wen 网络安全 203

本文目录导读:

XSS跨站脚本攻击如何有效过滤

  1. 核心原则:输出编码 > 输入过滤
  2. 输入验证(Input Validation) – 第一道防线
  3. 输出编码(Output Encoding) – 最核心的防御
  4. 内容安全策略(Content Security Policy, CSP) – 强安全头部
  5. 针对特定场景的防御
  6. 实战过滤工具与库(强烈推荐)
  7. 一个有效的过滤流程

针对XSS跨站脚本攻击的防御,核心原则是永远不要信任用户的输入,有效的过滤并非单一技术,而是一个多层防御体系,以下是从输入到输出的全链路有效过滤与防御策略。

核心原则:输出编码 > 输入过滤

最可靠的方法是输出编码(Output Encoding),而不是试图阻止恶意输入进入系统。 因为输入过滤很容易被绕过(例如使用不同编码、大小写变化等),而输出编码可以确保任何数据在展示时都只是普通文本,不会被浏览器解析为脚本。


输入验证(Input Validation) – 第一道防线

虽然不能完全依赖,但可以显著减少攻击面。

  • 白名单策略(最安全):
    • 只允许已知、安全的字符,手机号只允许数字、;用户名只允许字母、数字、下划线。
    • 禁止黑名单:不要试图去过滤 <script>、onerror 等关键词,攻击者有无数种绕过方式(如 <img src=x onerror=alert(1)> 可以写成 \x3cimg src=x onerror=alert(1)\x3e)。
  • 数据格式校验:
    • 数据类型:强制为整数、浮点数、布尔值。
    • 长度限制:合理限制输入长度,增加攻击成本。
    • 正则表达式:对于邮箱、URL、日期等,使用严格的正则匹配格式。

输出编码(Output Encoding) – 最核心的防御

这是应对XSS最有效、最通用的方法,根据数据放置的上下文,使用不同的编码方式。

输出位置 编码方式 示例 (以HTML为例) 说明
HTML标签内部 (如 <div>用户数据</div>) HTML实体编码 < → &lt;
> → &gt;
→ &quot;
→ &#x27;
& → &amp;
这是最常见的场景,确保所有动态文本都使用 textContent 而非 innerHTML。
HTML属性内 (如 <input value="用户数据">) HTML属性编码 除了HTML实体编码,还需对空格、制表符等特殊字符编码。 注意,不要用 包裹用户数据时,只需转义 本身。
JavaScript字符串内 (如 <script>var a = '用户数据'</script>) JavaScript转义 →
→
→
\n → \\n
极不推荐 在 <script> 中直接拼接用户数据,极易出错,优先使用 textContent 或 innerText。
URL参数内 (如 <a href="?page=用户数据">) URL编码(Percent Encoding) 空格 → %20
< → %3C
> → %3E
→ %22
必须先进行URL编码,然后再进行HTML属性编码(如果需要放在HTML属性中)。
CSS内 (如 <style> .user { background: url("用户数据"); } </style>) CSS转义 对所有非字母数字字符使用 加十六进制转义,如 → \27 除非绝对必要,永远不要将用户数据直接放入CSS。

重要提醒:现代Web框架(如React、Vue、Angular、Spring Boot、Django等)都内置了自动输出编码。只要使用模板引擎的标准语法(如 React 的 , Angular 的 ),就自动受到保护。 只有当你手动使用 innerHTML、v-html(Vue)、dangerouslySetInnerHTML(React)或拼接SQL字符串时,才会出现漏洞。

内容安全策略(Content Security Policy, CSP) – 强安全头部

CSP 是一个 HTTP 响应头,它告诉浏览器只执行来自特定来源的脚本,从而有效阻止内联脚本和执行恶意代码。

  • 基本配置:

    Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';
    • default-src 'self':只允许从同源(自己的域名)加载资源。
    • script-src 'self':只允许执行同源JavaScript文件。
    • object-src 'none':禁止 <object>、<embed>、<applet> 等插件。
  • 进阶配置(推荐):

    • 禁止内联脚本:script-src 'self' 已经禁止了 <script>alert(1)</script>。
    • 禁止 eval:script-src 'self' 'unsafe-inline' (默认允许,除非明确禁用) → 应使用 'unsafe-eval' 仅当需要时。
    • 使用 Nonce(一次性随机数):为可信的内联脚本生成一次性随机数。
      Content-Security-Policy: script-src 'nonce-{random-value}'

      HTML 中对应:

      <script nonce="{random-value}">alert('安全的内联脚本')</script>
    • 使用 Hash:对可信内联脚本内容计算哈希值。
      Content-Security-Policy: script-src 'sha256-{hash-value}'
  • 报告模式:先使用 Content-Security-Policy-Report-Only 排查问题,收集违规报告,确认无误后再切换为强制执行模式。

针对特定场景的防御

场景 防御措施
富文本编辑器(如 TinyMCE, CKEditor) 使用专门的 HTML 净化库 (如 DOMPurify, Bleach),这些库会解析HTML,移除所有不安全标签(如 <script>)、事件处理属性(如 onerror)、危险的 href(如 javascript:)等。
JSON 响应 确保 Content-Type 为 application/json,浏览器不会将其当作HTML解析。永远不要在 JSON 响应中直接返回用户输入作为 JavaScript 字符串,需进行 JSON 转义。
服务器端 vs 客户端 双重防御:服务器端必须做输出编码(因为客户端可能被禁用或篡改),客户端做辅助检查。
文件上传 将上传的文件存储在 不同的域名 下(如 upload.example.com, 而不是 www.example.com),避免同源策略下的XSS,不要直接显示用户上传的文件名作为 <img> 标签的 src,应将其作为资源ID,通过服务器端处理。

实战过滤工具与库(强烈推荐)

不要自己写过滤函数,容易遗漏,使用行业公认的库:

  • 前端 JavaScript:
    • DOMPurify:用于净化富文本HTML,支持配置白名单标签和属性,几乎所有现代富文本编辑器都依赖它。
    • sanitize-html:Node.js端的HTML净化器。
  • 后端:
    • Java:OWASP Java HTML Sanitizer 或 JSoup(用于富文本净化)。
    • Python:Bleach。
    • PHP:HTML Purifier。
    • .NET:HtmlSanitizer 库。

一个有效的过滤流程

  1. 源头控制:用户输入时进行白名单校验(如只允许字母数字)。
  2. 存储:按原样存储(不进行HTML转义存储,因为输出场景不同)。
  3. 输出(关键):
    • 普通文本:使用模板引擎的自动编码(如 )。
    • 属性值:使用属性编码。
    • URL:使用URL编码,然后嵌入到HTML中。
    • 富文本:使用 DOMPurify 或类似库。
  4. 全局控制:配置 Content-Security-Policy 头部。
  5. 定期审计:使用自动扫描工具(如 OWASP ZAP, Burp Suite)检测是否存在绕过。

一句话总结:永远不要在HTML、JavaScript、URL或CSS中直接拼接用户输入,使用框架的自动编码 + CSP + 合理的输入校验 = 最安全的防御。

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

友情链接攻略窝 · 礼包窝 · 配置窝 · 换算窝 · 算法窝 · 查文窝 · 手册窝 · 问答窝 · 全文搜 · 手册库
相关站点礼包窝 · 查文窝