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 防御方案中,有两种思路:
- 前后端穷举有限标签和属性,进行白名单过滤
这种方案,要求用户仅能输入指定、有限的标签和属性。前端可以通过富文本编辑器配置,仅显示指定标签,提升用用户体验。后端不能直接信任前端数据,需要基于白名单再次过滤,推荐使用 bleach 。这样可以保证,入库的数据都是可信任的。如果是 Django 工程,推荐使用 django-xss-cleaner。
适用场景:简单富文本输入。
- 后端转义存储,前端展示时,进行黑名单过滤
实际上,普通用户不会输入 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>
标签
配置示例:
只允许同源下的资源
|
|
允许同源以及指定地址的 JS 资源
|
|
多个资源时,后面的会覆盖前面的
|
|
如果是 Django 工程,推荐使用 django-csp。