目录

    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> 标签

    配置示例:

    只允许同源下的资源

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

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

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

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

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

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

    5. 参考