Please enable Javascript to view the contents

如何预防 Web 富文本中的 XSS 攻击

 ·  ☕ 3 分钟

1. XSS 原理和常见的几种攻击方式

XSS 攻击是指,通过执行恶意脚本,以实现窃取用户登陆态、劫持会话等目的的攻击方式。恶意脚本的输入源有,Cookies、Post 表单、Get 请求、HTTP 头内容等。通常,我们将一段 XSS 攻击的代码片段称之为 XSS 向量。

常见的 XSS 攻击类型有:

  • 反射型 XSS 。直接将 XSS 向量拼接在 URL 中,诱导用户点击。
  • 存储型 XSS 。通过表单,将 XSS 向量提交到数据库。当页面展示数据时,执行 XSS 向量。
  • DOM Based XSS 。通过修改浏览页面的 DOM ,绕过防御规则,执行恶意脚本,达到攻击目的。

XSS 攻击的一般路径是:首先找到页面上,文本回显的输入源,然后通过闭合标签,注入可执行的 JavaScript 脚本。

更多内容可以参考,XSS原理、构造

2. XSS 预防的思路方案

防御 XSS 攻击,主要是对文本内容进行 XSS Filter,阻止恶意脚本的执行。

XSS 过滤主要有两种模式:黑名单和白名单。

  • 基于黑名单的 XSS 过滤,将转义或移除黑名单中的标签和属性。
  • 基于白名单的 XSS 过滤,仅允许白名单中的标签和属性存在,其他全部转义或移除。

由于 XSS 的复杂多变,无法穷举全部 XSS 攻击向量,基于黑名单的 XSS Filter 不够安全。而基于白名单的 XSS Filter ,需要穷举允许的全部标签和属性,配置繁琐。这也是为什么 XSS 如此泛滥的原因:没有一个能低成本实施、对用户输入无影响的 XSS 防御方案。

另外一种预防的方式就是阻止恶意脚本的执行。也就是允许恶意脚本存在,但是不允许其执行。例如,在 Vuejs 中,v-text 指令会将 XSS 向量展示在页面上,不执行 XSS 向量,也就不会触发攻击行为。但是,当允许用户输入样式时,我们会使用 v-html 指令将用户输入的内容显示在页面上。这就可能导致 XSS 攻击。我们需要进一步的防御措施。

3. XSS 预防的方案

存储型 XSS 能够进行蠕虫攻击,危害极大,是 XSS 预防的重点。在我接触的富文本 XSS 防御方案中,有两种思路:

  1. 前后端穷举有限标签和属性,进行白名单过滤

这种方案,要求用户仅能输入指定、有限的标签和属性。前端可以通过富文本编辑器配置,仅显示指定标签,提升用用户体验。后端不能直接信任前端数据,需要基于白名单再次过滤,推荐使用 bleach 。这样可以保证,入库的数据都是可信任的。如果是 Django 工程,推荐使用 django-xss-cleaner

适用场景:简单富文本输入。

  1. 后端转义存储,前端展示时,进行黑名单过滤

实际上,普通用户不会输入 XSS 向量,而攻击者可以很轻松地使用 Postman 或 Burp Suite
进行安全测试。第二种思路是,完全不信任数据输入,但又不能破坏用户数据。于是,直接将用户输入的数据转义入库,然后反转义输出,保证数据库中的内容是可信任的。展示数据时,前端对展示的内容进行基于黑名单的过滤,推荐使用 js-xss 。

适用场景:对输入标签范围不定,富文本编辑功能复杂。

4. CSP

除了在内容上使用 XSSFilter 进行过滤,还可以使用 HttpOnly、CSP 头部进一步预防 XSS 攻击。

CSP (Content Security Policy) 是用来防御 XSS 的安全策略。CSP 通过白名单控制,仅允许加载指定的资源。这些资源包括 JavaScript, CSS, HTML, Frames, fonts, image, embeddable object, Java applets, ActiveX, audio 和 video 等。

有两种方法可以启用 CSP :

  • 设置 HTTP 头信息的 Content-Security-Policy 字段
  • 在网页添加 <meta> 标签

配置示例:

只允许同源下的资源

1
Content-Security-Policy: default-src 'self';

允许同源以及指定地址的 JS 资源

1
Content-Security-Policy: script-src 'self' www.google-analytics.com ajax.googleapis.com;

多个资源时,后面的会覆盖前面的

1
Content-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self';

如果是 Django 工程,推荐使用 django-csp

5. 参考


微信公众号
作者
微信公众号