写点什么

Dropbox 的 Web 安全防护策略之二:unsafe-inline 指令和随机数配置

  • 2015-12-01
  • 本文字数:3785 字

    阅读完需:约 12 分钟

【编者的话】Dropbox 的 Web 安全防护措施之一是使用基于内容的安全策略(CSP)。Dropbox 的安全工程师 Devdatta Akhawe 通过四篇文章,介绍了 CSP 在 Dropbox 中推广的细节和经验。Dropbox 的 CSP 原则大大减少了 XSS 和内容注入攻击。不过,大规模使用比较严苛的 CSP 规则将面临诸多挑战。我们希望通过这四篇 CSP 系列文章,将 Dropbox 在实践 CSP 过程中的收获分享给广大开发社区朋友。第一篇文章主要介绍如何在规则中设置报表筛选管线来标记错误;第二篇介绍 Dropbox 如何在上述规则中配置随机数及缓解unsafe-inline带来的安全风险;第三篇介绍如何降低unsafe-eval造成的风险,以及介绍 Dropbox 所开发的开源补丁;最后一篇介绍在权限分离机制下,如何减小第三方软件整合时的风险。本篇是该系列文章的第二篇,主要介绍 Dropbox 的随机数配置,还有 unsafe-inline 指令所带来的问题及解决方法。

第一篇文章中,我们讨论了如何筛选错误报告及如何利用CSP 为网站配置内容源白名单。通常而言,白名单中最重要的内容源是代码源,代码源由 script-srcobject-src指令确定。标准的 CSP 配置一般含有一个受信任域名的列表,其中包括主网站名和可靠 CDN 等,它们由script-src及其他诸如unsafe-inlineunsafe-eval的指令给出。

这种规则阻止了随意注入的第三方脚本,但又由于有unsafe-inline这项指令存在,它并不能有效地防止 XSS 攻击。如果读者对unsafe-inlinenonce-src尚不熟悉,建议参阅这篇介绍文章。简而言之,CSP 默认阻止所有内联脚本区块和内联事件( < div onclick="somescript" >),加强了代码和数据的分离。所有运行在网页中的代码必须来自白名单中的源所提供的脚本文件。这样便大大降低了 XSS 攻击的风险,但同时也需要巨大的移植工作量。

为了使移植变得简便,规则中允许一类特殊的源指令句法,它适用于script-srcstyle-src指令,如果含有匹配的随机数属性,那么则接受内联内容。这样, script-src源列表中含有nonce-randomnumber的规则就可以允许执行将“randomnumber”作为随机数属性值的脚本标记。随机数句法是 CSP2 的一部分,现在仅仅在 Chrome 和 Firefox 中支持。而在其他浏览器中,使用内联脚本标记需要用unsafe-inline使能所有内联脚本。

本篇文章将讨论我们在 Dropbox 网站上配置随机数的经验。在进入细节讨论之前,必须强调 CSP 只是一项缓解措施,并不能取代严格的验证及清理净化工作。Dropbox 服务器和客户端分别使用的库是 Pyxl React ,客户端的 HTML 清理使用的库则是 DOMPurify

配置脚本随机数

配置脚本随机数包含两个步骤:一、给所有内联脚本标记加上对应的随机数;二、移除所有内联事件处理器。Dropbox 使用 Pyxl 生成服务器端的 HTML。Pyxl 将 HTML 标签转换为 Python 对象,在清理过程中自动去除非可信数据。我们调整了一些 Pyxl 清理代码,以便在脚本标记中插入正确的脚本随机数。

第二步移除内联事件处理器比较困难。有较长的一段时间我们极力反对使用内联事件处理器,Dropbox 上新写的代码也没有它们,但这仍然造成了大量旧代码没有办法移植。为了减少过渡阶段的工作量,我们决定自动重写内联事件处理器来使用内联脚本标记。最基本的例子如下,原来的代码<div id="foo” onload="somescript">变为:

复制代码
<div id="foo"><!-- if id is absent, we create a unique id -->
<script>
// The nonce in the script tag above will be
// inserted during Pyxl serialization
function(){
var e = document.getElementById(foo);
e.addEventListener("load", function(ev){
// ...somescript..
});
}();
</script>

上述例子有几个值得关注的点。首先,我们使用了即时调用函数表达式,这样不会造成全局命名空间的混乱。第二,我们插入了一个脚本标记,它在原本的标记打开后加入了onload事件处理器。通常的加入操作是在原来的 div 元素结束或DOMContentLoaded事件之后,虽然它们也可能有很好的特性,但我们修改后的代码已经很接近浏览器原来的性能,因此这里我们使用的方法适用于自动转换。

读者们可能仍然会有疑问:以上转换没有在onload代码中修复已有的 XSS 攻击,所以并不是完全安全的转换。然而,我们认为这种危险是在可接受范围内,因为像 Pyxl 之类的系统,已经可以很好地识别并阻止在服务器的代码中的 XSS。另外,随着时间的推移,我们仍将舍弃内联事件处理器,从而彻底规避这类风险。

通过上述的代码转换,只有在我们掌控中的内联脚本和事件处理器会执行。如果一次攻击尝试插入事件处理器(比如使用了 DOMXSS 等),支持随机数属性的浏览器将会阻止这类攻击。

内联脚本错误报告

和所有的 CSP 配置一致,推出一个新的随机数属性通常的做法是先在 report-only 模式下运行。Dropbox 使用 report-only 模式将近一个月。同样也和内容源错误报告一样,内联脚本错误中的噪声滤除也十分重要。

除了上篇文章中提到的技巧,Chrome 通过发送另外两项内容域(fields)来辅助识别内联脚本错误:脚本样本和源文件。脚本样本对于代码库中的快速查找十分关键,因为在本地重现问题较为困难。源文件则指的是通过 DOM API 插入内联脚本的 JavaScript 源文件。在筛选内联脚本错误阶段,我们过滤掉所有源文件域为 URI 的报告,这类错误报告不属于当前讨论的应用范围(广告插入和扩展工具是一类普遍的错误源)。类似地,参照 Neil 的建议,有些报告的脚本样本中包含的明显不是自己应用的代码(比如,脚本中包含字符串“lastPass”),我们也过滤掉了这一类错误报告。

Firefox 有一个程序缺陷:即便 nonce src允许执行内联脚本,Firefox 仍会上报错误,同时也在执行代码。因此我们建议,为了减少噪声,在配置随机数时删除 Firefox 的report-uri

更新:这个程序缺陷已经修复了!不过修复的版本是 2015 年十月发布的 Firefox 43,我们建议在 2016 年 1 月之前,不要为 Firefox 发送report-uri

利用合适的过滤器,我们给我们的规则配置了随机数源,而且开始查找错误并修复。对于像 Dropbox 这样巨大的规模和所拥有的代码库来说,这个过程十分枯燥。但是这项任务的回报值得我们做出努力,而且工作量也并非无法计算。经过几周的努力,我们成功地在执行模式下配置了nonce-src

无随机数支持下 DOMXSS 攻击的缓解

比较可惜的是,随机数源是 CSP2 中的功能。虽然 Chrome 和 Firefox 已经支持随机数源一段时间了,但 Safari 及 Edge 仍未支持。Safari 和 Edge 都没有随机数源句法,却强化了unsafe-inline源表达式。为了使我们的网页应用性能更好,我们使用了另一个技巧:

复制代码
document.addEventListener('DOMContentLoaded', function () {
var metaTag = document.createElement('meta');
metaTag.setAttribute('http-equiv', 'Content-Security-Policy');
metaTag.setAttribute('content', "script-src https: 'unsafe-eval';");
document.head.appendChild(metaTag);
});

简单地说,在浏览器执行所有 HTML 和同步脚本(包括内联脚本)后,激发 DOMContentLoaded 事件。在此之后,其他的 JavaScript 任务和事件进行排队,或者激发其他的 onload 处理器。随后的操作性能得到最大化,我们不再同时执行远程脚本,所以大部分 JavaScript 代码都在DOMContentLoaded之后执行。

上面展示的代码在DOMContentLoaded激发之后,插入了第二代 CSP 规则。需要特别说明的是,第二代 CSP 规则没有“unsafe-inline”。浏览器处理多个 CSP 规则时会强制遵循所有规则,只有符合全部规则的代码才能够得以执行。因此,在DOMContentLoaded事件激发之前,Safari 和 Edge 仅在初始 HTML 中解析并支持内联脚本。DOMContentLoaded激发之后,这两个浏览器便停止支持内联事件处理器。

设想一下,在某次攻击插入了含有恶意有效载荷(<div onclick=alert(1)>)。Chrome 和 Firefox 中的规则包含标头传递的随机数,可以阻止内联 onclick。而在 Safari 和 Edge 中,第一个规则允许onclick处理器,DOMContentLoaded事件后插入的第二个规则阻止onclick。尽管这种保护相对于支持随机数源的浏览器中的保护措施较为薄弱,但它仍然阻止了大量的 DOMXSS 攻击。

最后的思考

上面提到的方法有效地缓解了 Dropbox 网页应用受到的 XSS 攻击。在 Chrome、Firefox、Safari 还有 Edge 等浏览器中,我们的大量用户受到的网页攻击也得到了适当地减轻。我们修复了所有注入漏洞,也为我们大多数用户修筑了二次防线以抵御更强的注入攻击。

配置像 CSP 这样重要的工程,尤其还要舍弃“unsafe-inline”,需要全公司的鼎力支持。感谢参与该项目的所有 Dropbox 成员,特别是安全工程团队的小伙伴们。这篇文章是实践 CSP 系列文章中的第二篇。下一篇,我们将介绍在规则中加入unsafe-eval的影响,以及如何它所带来的降低风险。

查看英文原文: [CSP] Unsafe-inline and nonce deployment

编后语

《他山之石》是 InfoQ 中文站新推出的一个专栏,精选来自国内外技术社区和个人博客上的技术文章,让更多的读者朋友受益,本栏目转载的内容都经过原作者授权。文章推荐可以发送邮件到 editors@cn.infoq.com。


感谢魏星对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群(已满),InfoQ 读者交流群(#2))。

2015-12-01 16:393916
用户头像

发布了 268 篇内容, 共 134.2 次阅读, 收获喜欢 24 次。

关注

评论

发布
暂无评论
发现更多内容

世界首台人工智能地震监测系统问世;AAAI 2021 | 利用深度元学习对城市销量进行预测

京东科技开发者

大数据 红帽

来,在图片上画个矩形吧,取经之旅第 14 天

梦想橡皮擦

3月日更

书单|互联网企业面试案头书之数据分析师篇

博文视点Broadview

可视化开发:前端按时下班不再是问题

华为云开发者联盟

大前端 框架 交互 渲染引擎

万物皆可拆

小匚

产品经理训练营作业 06

KingSwim

Python API 类型系统的设计与演变

李宇飞

API

我还不懂什么是分布式事务

好好学习,天天向上

Java MySQL spring 分布式 事务

MySQL主从原理,基于快速学习一门技术的3种方式

博文视点Broadview

EGG Network公链生态应用EFTalk阿凡提

币圈那点事

史上最全教程:idea将Java项目打包Jar包,并生成exe可执行文件

madison

Java jar包转exe可执行文件 exe4j

作业8

瑾瑾呀

如何避免水肥一体化过量灌溉?开启智慧管理,一个屏幕轻松搞定

一只数据鲸鱼

物联网 数据可视化 智慧城市 智慧农业

区块链农产品溯源系统开发,区块链农产品溯源平台的搭建

13828808769

区块链 区块链+ #区块链#

AA

郑伟

标签

2020 年前端技术发展盘点

三钻

发展 大前端 组件化 机会与趋势

智慧社区服务平台的搭建,助力老旧小区改造

13828808769

智慧终端

第九章学习总结

Kalman

产品经理 产品经理训练营

缓存不一致、缓存雪崩、缓存击穿、缓存穿透

escray

redis 学习 极客时间 3月日更 Redis 核心技术与实战

科普NA公链(Nirvana):NAC公链采用基于NIO的Netty,实现链上应用百万级TPS并发​

区块链第一资讯

无需编程,通过配置零代码生成CRUD RESTful API

crudapi

RESTful 低代码 API crud crudapi

区块链在医疗领域的应用场景,区块链+医疗的解决方案

13828808769

区块链 区块链+ #区块链#

从相识到相惜:Redis与计算存储分离四部曲

华为云开发者联盟

数据库 redis 华为云 存算分离 GaussDB ( for Redis )

第九章作业

Kalman

产品经理 产品经理训练营

聊聊Java的异常机制问题

华为云开发者联盟

Java 对象 异常机制 Throwable Error

Kafka、RabbitMQ、RocketMQ 之间的区别是什么 ?

AI乔治

Java kafka 架构 消息队列

推进智能变革,HPE让零售业的数字化梦想照进现实

Lily

图片的黑魔法——GitHub 热点速览 v.21.13

HelloGitHub

GitHub 开源

华为云副总裁薛浩:云原生视频服务,重塑体验,助力产业升级

华为云开发者联盟

云原生 音视频 视频 华为云 AR/VR

企业迁移到云服务时要考虑的六大问题

云计算

Firebase 命令行工具

HoneyMoose

Dropbox的Web安全防护策略之二:unsafe-inline指令和随机数配置_安全_张天雷_InfoQ精选文章