BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

Dropbox的Web安全防护策略之三:意外Eval操作

| 作者 张天雷 关注 4 他的粉丝 发布于 2015年12月9日. 估计阅读时间: 12 分钟 | ArchSummit北京2018 共同探讨机器学习、信息安全、微服务治理的关键点

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

在之前的两篇文章中,我们讨论了Dropbox如何大规模配置CSP来防止注入攻击。第一篇文章主要讨论的是如何筛选错误报告,获得噪声较小的白名单,从而限制应用中运行的代码源;第二篇文章主要讨论,随机数源如何缓解内容注入带来的XSS攻击。尽管如此,CSP规则中的另一个关键字unsafe-eval允许字符串转代码的用法(比如,evalnew FunctionsetTimeout等),这又留下了XSS攻击的隐患。

显然,上面这个问题必须解决。但由于旧式JS模板在Dropbox客户端代码中的大量使用,全面禁止eval并不容易。在我们用React替换旧式模板的过程中,我们也在思考unsafe-eval造成危险的确切机理和解决方法。

unsafe-eval乍看起来并不像致命的不安全指令。unsafe-eval只决定浏览器是否允许eval,其变量类似于new Function。但是,如果一次攻击中可以调用eval,那么这次攻击就已经到达了代码执行的程度,这必会造成损失。与unsafe-inline不同,在unsafe-eval造成的漏洞中,攻击插入字符串并随字符串进入eval“槽”,而unsafe-inline则允许攻击者将简单的HTML注入漏洞转变为代码注入漏洞。

不幸的是,在更深入的探索中我们意识到,上述解释并不正确。产生攻击漏洞的主要原因是我们使用了jQuery、Prototype之类的库。事实上,使用jQuery、Prototype时,unsafe-eval抵消了移除unsafe-inline所带来的优势。我们会深入讨论jQuery,类似的问题也同样存在于Prototype或其他库中。

请看以下两行HTML代码,似乎它们的运行结果相同:


document.getElementById("notify").innerHTML = untrusted_input
jQuery("#notify").html(untrusted_input)

不允许内联脚本的CSP规则中,untrusted_input可能含有全局中所有的onclicks,浏览器不会执行它们。这一点对于两行代码都适用。但是untrusted_input包含一个内联脚本标记(如,alert(1)),这就使得两行代码大不相同了。

在第一行代码中,innerHTML不支持内联脚本标记,alert不会执行。而在第二行代码中,jQuery将解析脚本标记,直接用innerHTML设置untrusted_input并不会起作用。jQuery会解析脚本标记,并直接在脚本标记中eval代码。更糟糕的是,如果untrusted_inputhttps://attacker.com/foo.js,那么jQuery会XHR注入那个foo.js文件并eval它,内容源对脚本的限制甚至会失效。完成这一动作的代码在jQuery核心的domManip函数中。jQuery代码在几乎所有DOM操作(插入、追加、html等)中,都会调用该函数。

此类问题的另一个例子是jQuery.ajax函数。这个函数看起来是一个普通的用来产生XHR请求的函数,但jQuery从设计上赋予了它的ajax函数更多功能。特别当XHR请求的应答中包含内容型脚本时,jQuery会eval应答(参见GitHub讨论)。这意味着,只要是攻击者可以控制目标ajax URI的地方,都将成为代码注入漏洞。

不允许eval的CSP规则中,浏览器会阻止上述的漏洞。但实施这种CSP规则代价巨大。为了减少此类风险,我们开发了一项jQuery顶层“安全补丁”,以防止非安全操作。我们很乐意将我们的jQuery补丁开源来帮助解决以上“意外的eval操作”,希望广大的社区开发者们可以从中受益。如果开发者朋友们发现其他地方需要打补丁,也请和我们分享!

补丁中有两个重要的组成部分。首先,通过添加以下代码,移除了ajax中的隐式eval。这行代码使用一个no-op代替了脚本应答的默认处理器(放置在jQuery代码使用eval的地方)。


jQuery.ajaxSettings.converters["text script"] = true

第二,重写了默认的domManip函数,在执行前检测脚本标记及随机数的正确性。补丁仅仅重新实现了domManip函数(完全从jQuery中复制出来),不过补丁的关键之处在函数的第183行:


// line 181:
               for (i = 0; i < hasScripts; i++) {
                    node = scripts[i];
                    if ((window.CSP_SCRIPT_NONCE != null) &&
                     (window.CSP_SCRIPT_NONCE !== node.getAttribute('nonce')) {
                          console.error("Refused to execute script because CSP_SCRIPT_NONCE" +
                          " is defined and the nonce doesn't match.");
                          continue;
                      }

另外一种解决方案是完全删除可能造成误操作的代码,或使用jPurify等插件清理jQuery所有的DOM操作。但文章这里的重点是,如果配置的CSP规则允许unsafe-eval,那么减小XSS攻击风险的措施便十分重要。

可信任eval的使用

正如之前所提到的那样,因为我们早先的代码仍在使用不安全的eval,我们无法完全移除规则中的unsafe-eval。特别地,当使用JavaScript Microtemplates时,我们还需要unsafe-eval。本质上,该模板库使用new Function来对“text/template”内容型脚本标记中的模板进行eval操作。例如下面这个模板


<script type="text/html" id="user_tmpl">
  <% for ( var i = 0; i < users.length; i++ ) { %>
    <li><a href="<%=users[i].url%>"><%=users[i].name%></a></li>
  <% } %>
</script>

模板代码使用id参数查找模板,然后在上面的脚本标记中调用new Function函数,但这样也使得攻击者可以用HTML注入漏洞插入恶意模板。这里的模板是由我们的模板库eval所得。

为了解决这个问题,我们在所有模板脚本标记中插入随机数属性,并修正了模板库,检查模板节点的随机数属性。这类似于浏览器检查脚本节点的随机数属性。


<script id=test type=text/template nonce=1234>
...// template library only processes this if 
...// window.CSP_SCRIPT_NONCE equals 1234
</script>
<script type=text/template>
...//the templating library will ignore this
</script>

我们遇到的另一个问题是,有时客户端代码会在网页载入之后下载模板。由于服务器每次生成一个新的随机数,网页载入后下载下来的模板中的随机数会和主页中的随机数不一样。我们通过修改服务器端的代码解决了这个问题。以前每次载入都要产生随机数,现在替代的方法是,网页的脚本随机数是CSRF令牌的hash值(CSRF令牌已经是一个不可预测的随机值了)。这个方法将随机数安全性简化为CSRF令牌安全性。不过,如果攻击者知道使用的是CSRF 令牌,可能对用户进行CSRF攻击。

最后再一次提醒读者,CSP是一个缓解风险的措施,属于深度防御,并不是网页应用安全的第一道防线。最适合XSS的防御方法是安全搭建HTML,使用的框架应当能够自动规避非信任数据,同时使用性能较好的DOM清理器作为第二道防线。

在下一篇文章中,我们将讨论CSP和第三方软件整合的问题,及其相关的风险。

查看英文原文:[CSP] The Unexpected Eval

编后语

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


感谢魏星对本文的审校。

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

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT