写点什么

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:393484
用户头像

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

关注

评论

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

推动SiCMOSFET国产化,华秋获“芯塔电子”优秀媒体合作伙伴奖

华秋电子

一文教会你!如何利用火焰图快速定位内存泄漏?b

Greptime 格睿科技

数据库 rust 内存泄漏

k8s探针详解

EquatorCoco

Kubernetes k8s 容器化

如何利用 APM 追踪完整的类函数调用

观测云

性能优化

Flask请求与响应-视图函数处理请求数据

测试人

软件测试 测试 自动化测试 测试开发

1688公司档案信息数据接口采集Python

tbapi

1688API接口 1688公司档案信息接口

ICDM'23 BICE论文解读:基于双向LSTM和集成学习的模型框架

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟 论文解读

测试管理训练营马上开营! 快来免费领取试听课吧~

测试人

软件测试 测试 自动化测试 测试开发

Solidity案例详解(一)存钱罐合约

BSN研习社

区块链 Solidity

K8S学习指南(4)-minikube的使用

俞兆鹏

React Native性能优化指南

第五代英特尔至强可扩展处理器以强劲性能,打造更“全能”的计算

E科讯

解读|如何利用 NFTScan 解锁当前 NFT 生态走势

NFT Research

NFT\ NFTScan NFT开发

低代码为何这么“香”

华为云开发者联盟

低代码 开发 华为云 华为云开发者联盟 华为云Astro

微信多开助手for mac下载

iMac小白

【好文翻译】JavaScript 中的 realm 是什么?

OpenTiny社区

前端 OpenTiny

1688店铺联系方式API接口文档

tbapi

1688API接口 1688店铺联系方式接口

低功耗DC-DC电源模块的精细化PCB设计

华秋电子

面试官:SpringBoot如何实现缓存预热?

王磊

Java 面试

云行| 国云筑基 焕新启航,天翼云中国行·东莞站圆满举行!

天翼云开发者社区

云计算 数字化 云电脑

住宅代理IP在保护品牌形象中起到关键性作用

摘星星的猫

如何利用容器与中间件实现微服务架构下的高可用性和弹性扩展

天翼云开发者社区

架构 微服务

分布式系统中的分布式链路追踪与分布式调用链路

天翼云开发者社区

分布式系统 网络

淘宝/天猫店铺商品详情 API 实现实时数据获取:快速、稳定、高效

Noah

集合-Java-笛卡尔积、平铺

alexgaoyh

Java 集合运算 笛卡尔积 数据平铺

Flink Kubernetes Operator 介绍

数新网络官方账号

flink

工作中使用Redis的10种场景

快乐非自愿限量之名

数据库 redis 前端 开发

与达沃斯同行 | XTransfer与达沃斯百位全球创新者“头脑风暴”

XTransfer技术

揭秘代币价值:Token Explorer 带您洞察市场,把握投资先机

Footprint Analytics

Token 代币

师爷,翻译翻译什么叫AOP

不在线第一只蜗牛

Java 数据库 前端 aop

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