BT

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

Dropbox的Web安全防护策略之四:第三方接入与权限分离

| 作者 张天雷 关注 4 他的粉丝 发布于 2015年12月16日. 估计阅读时间: 12 分钟 | 如何结合区块链技术,帮助企业降本增效?让我们深度了解几个成功的案例。

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

在本系列之前的几篇文章中,我们讨论了Dropbox配置CSP的经验,着重介绍了控制脚本源的script-src指令。通过锁定脚本源白名单、配置随机数源以及限制unsafe-eval风险等措施,Dropbox的CSP规则有效地缓解了XSS注入攻击。在所支持的浏览器中,只有来自于我们自己的网站、CDN或其他受信第三方的代码可以在Dropbox的网页应用中运行。

然而,配置CSP同时使用第三方接入又有其特有的风险与挑战。在本篇文章中,我们会讨论如何用HTML5权限分离的方法来解决此问题。

第三方接入的风险

首先举一个例子来说明在我们网站上运行的第三方接入代码:企业版Dropbox中有一个SnapEngage提供的即时聊天小工具,根据网页应用与SnapEngage集成的机制,我们在HTML页的脚本节点中插入了以下代码。


var se = document.createElement('script');
se.type = 'text/javascript';
se.async = true;
se.src = '//storage.googleapis.com/code.snapengage.com/js/' + chatId + '.js';
se.onload = se.onreadystatechange = function() { ... //elided 
var s = document.getElementsByTagName('script')[0]; 
s.parentNode.insertBefore(se, s);

上面的代码生成了指向SnapEngage库的脚本节点,同时设置了onload处理器,并将节点插入到页面中。载入的JavaScript库接下来生成显示聊天工具的标记和相关的事件处理器,并把它们插入到页面中。

这一过程存在着两个关键的问题。首先,聊天工具的标记和事件处理器并未使用CSP规则,因此,如果聊天工具使用了eval或内联事件处理器,我们的CSP规则便会阻止启动聊天工具。当我们第一次在Dropbox网站上为script-src配置随机数时,嵌入了聊天工具的页面不得不禁用CSP规则,这也就增加了页面遭受XSS攻击的风险。

另一个问题是一个不易察觉的威胁:该过程增加了Dropbox的可信计算基,最终包含了SnapEngage的服务器。根据同源策略,所有运行在www.dropbox.com源上的代码拥有相同的权限。增加可信计算基实质上隐性地增加了安全风险。未来的网络平台提升方法可以降低这一类的安全风险,但该方法目前仍在万维网联盟(W3C)内部讨论。

我们很了解上述风险,Dropbox第三方接入的提供者也对自身进行了全面审查,并且强制执行了安全条约。但在实际中,仍然存在某些第三方提供者并未认真执行安全检查的情况,本着对用户负责的态度,我们认为此类数据安全风险过高无法接受,必须采取相应措施降低风险。

对此,一个可行的解决方案是,只将接入代码复制到我们的服务器中,同时修改聊天工具,使之去掉内联事件处理器。然而这种侵入式的解决方法代价巨大,更为糟糕的是,只要聊天工具升级更新,Dropbox就必须人工进行检查和提交代码。如果将这个步骤自动完成,那么同样会产生许多安全隐患。

补救方法:权限分离

我们使用权限分离的方法来解决第三方接入所带来的问题,其核心思想很简单:在无权限的源(origin)中运行第三方代码,避免了直接在Dropbox源中运行第三方代码。第三方代码通过iframe接入网站,iframe间的通信使用postMessage函数。Dropbox源提供更小的受信API,在不降低安全性的前提下保证了相关功能。

这同OpenSSHGoogle Chrome的权限分离架构很类似,无权限的子进程与无权限的源通信,有权限的进程与有权限的(Dropbox)源通信。不过与库应用中使用的IPC机制不同,我们使用postMessage实现iframe间的通信。

具体来看一下SnapEngage接入到底怎样做到了权限分离。当载入一个含有SnapEngage聊天工具的网页时,https://www.dropbox.com源中的代码生成一个指向https://www.dbxsnapengage.com的iframe。接下来,dbxsnapengage.com上的代码载入SnapEngage聊天工具。iframe自带的CSS隐藏聊天工具的边框,看起来聊天工具便和Dropbox网页天衣无缝地组合在了一起。

当然,这种方法的效率并不高。为了维护相关功能,聊天工具需要和主页集成。比方说,我们希望只在用户点击页面顶端的“Chat”按钮时,聊天工具才显示出来。之前的JavaScript代码通过监测“Chat”按钮上的按键动作,调用startSupportChat函数来实现该功能。


function startSupportChat() {
    SnapEngage.setWidgetId(SUPPORT_ID);
    SnapEngage.setUserEmail(chatData.Email, true)
    SnapEngage.startChat("How can we help you today?")
}

startSupportChat函数会调用初始化聊天功能的相关SnapEngage代码。由于SnapEngage代码运行在dbxsnapengage.com上,这个函数并没有产生任何效果,也不存在于www.dropbox.com当中。我们对此的做法是,在www.dropbox.com上修改代码来给iframe发送消息。


DropboxSnapEngage.startSupportChat = function() {
    this.chatRequested = true;
    DropboxSnapEngage.showSnapEngageIframe();
    return DropboxSnapEngage.sendMessage({
        'message_type': 'startSupportChat',
        'chatData': this.chatData
    });
};

DropboxSnapEngage.sendMessage = function(data) {
    var content_window;
    content_window = DropboxSnapEngage.getSnapEngageIframe().contentWindow;
    return content_window.postMessage(data, this.SNAPENGAGE_IFRAME_ORIGIN);
};

上述代码给dbxsnapengage.com的iframe发送消息。接着,dbxsnapengage.com通过定义下面的postMessage事件处理器来调用startSupportChat函数。


function receiveMessage(event) {
     if (!validOriginURL(event.origin)) return;

     var data = event.data
     switch (data.message_type) {
//elided ...
         case "startSupportChat":
             startSupportChat();
             break;
//elided ...
     }
 }

最终的效果为,点击“Chat”按钮后将显示iframe,并给聊天工具代码发送消息以启动聊天功能。所有的聊天工具代码都运行在无Dropbox权限的dbxsnapengage.com源中。

以上所讲的仅仅是一个例子,我们在Dropbox网站中不同的位置都使用了权限分离的方法,有效地降低了第三方接入(例如,支付服务提供商的接入)所带来的风险。另外,作为第三方提供者的SnapEngage不需要做任何的改动,可以继续使用内联事件处理器。这个设计的特点虽然看起来微不足道,但事实上非常重要。我们拥有并运营着dbxsnapengage.com域名,也开发完成了跨权限的postMessage API。

查看英文原文:[CSP] Third Party Integrations and Privilege Separation

编后语

《他山之石》是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