存储型XSS如何拦截

wen 网络安全 30

本文目录导读:

存储型XSS如何拦截

  1. 输入过滤与消毒(数据入库前)
  2. 输出转义与编码(数据出库前)
  3. 内容安全策略(CSP)(兜底方案)
  4. 其他辅助措施
  5. 四层防御体系

针对存储型XSS(Stored XSS)的拦截,核心思路是在数据进入数据库时进行消毒,并在输出到浏览器时进行转义,同时配合内容安全策略(CSP)作为最后一道防线,以下是具体的拦截方案:

输入过滤与消毒(数据入库前)

这是最关键的环节,目标是在用户提交数据时,移除或转义潜在的恶意脚本。

  • 白名单策略:只允许特定的、安全的标签和属性(如 <b><i><a>href 只允许 http/https 协议),这是最推荐的方式。
  • 黑名单过滤:过滤常见的XSS攻击载荷,如 <script>onerrorjavascript: 等。但黑名单很容易被绕过(例如使用大小写、编码、<img src=x onerror=...>),仅作为辅助手段。
  • 使用成熟的库:不要自己写正则过滤,使用经过验证的库:
    • Java:使用 OWASP Java EncoderJsoupJsoup.clean() 方法可以非常方便地只保留安全标签)。
    • Python:使用 bleach 库,它基于HTML5lib,能有效解析并清理恶意代码。
    • PHP:使用 HTML Purifier
    • Node.js:使用 DOMPurify(可在服务端使用)。

输出转义与编码(数据出库前)

即使输入过滤不完美,只要在输出时正确转义,攻击代码就不会被浏览器执行。

  • 上下文敏感的编码:根据数据插入的位置选择不同的编码方式:
    • HTML元素内容(如:<div>用户输入</div>):对 < > & " ' 进行HTML实体编码,大多数模板引擎(如Thymeleaf、Jinja2、Vue的)默认会做这件事。
    • HTML属性(如:<input value="用户输入">):对 、&<> 进行编码。
    • JavaScript环境(如:<script>var x = "用户输入"</script>):必须对 、、、换行符等进行JavaScript字符串转义
    • URL参数(如:<a href="用户输入">):使用 URL编码(如 encodeURIComponent())并只允许http/https协议(防止 javascript: 伪协议)。

内容安全策略(CSP)(兜底方案)

即使1和2都失效,CSP是阻止XSS执行的最强技术手段,通过在HTTP响应头中设置策略,浏览器会拒绝执行非白名单的脚本。

Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline';
  • 关键点绝对不要允许 'unsafe-inline'eval()(除非绝对必要),如果使用了内联脚本,应使用 noncehash 机制。
  • 存储型XSS特别建议:对用户生成的内容(如评论区、帖子),考虑使用 sandbox 属性或将其放在隔离的iframe中,限制其执行JavaScript的能力。

其他辅助措施

  • HttpOnly Cookie:虽然不能阻止XSS注入,但可以防止攻击者通过document.cookie窃取会话令牌,对所有会话Cookie必须设置HttpOnly
  • 设置 X-XSS-Protection: 0:现代浏览器已经废弃了老的XSS过滤器(XSS Auditor),该特性在Chrome中已被默认禁用,关闭它可以避免误阻断和新的绕过问题,防御应依赖CSP。
  • 验证富文本内容:如果允许用户使用富文本编辑器(如TinyMCE、Quill),输出前需使用服务端的HTML清理库(如Java的Jsoup、Python的bleach)再次清洗,因为编辑器本身的过滤很容易被通过请求篡改绕过。

四层防御体系

  1. 第0层(预防):输入校验,严格限制数据类型(如邮箱、数字长度),并拒绝不符合格式的数据。
  2. 第1层(核心):输入消毒,使用白名单库(如 Jsoup.clean())清理富文本内容。
  3. 第2层(必备):输出转义,根据上下文(HTML、属性、JS、URL)使用对应的编码函数。
  4. 第3层(兜底):CSP,仅允许执行受信任的脚本源,从根本上阻止恶意代码的执行。

最终建议:不要完全依赖输入过滤(因为总有未知的绕过方式),必须做好输出编码,并一定要加上CSP策略作为最后一道防线。

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