谷歌CSP工程化实践导读
*本文作者:Wester,就职于腾讯安全平台部,从事研发安全相关工作,欢迎联系探讨(https://zhuanlan.zhihu.com/p/66652397)
引子
内容安全策略(Content Security Policy, 以下简称CSP)是业界主推的前端安全纵深防御方案。针对XSS漏洞及其他前端安全风险,其显著效果,已经在广泛应用中证实。
作为CSP规范的核心制定与实践者之一,Google团队在今年的HITB安全会议上进行了题为《A Successful Mess Between Hardening and Mitigation》的分享,其中呈现的数据与经验颇具参考意义。
为方便快速浏览,笔者在忠于原文基础上,辅以深度讲解,形成导读共享。全文分为四部分:精粹导览、知识背景、议题解读和总结。其中,“精粹导览”是对议题内容的客观精粹,“议题解读”呈现了笔者基于理解的综合评述。运营/决策者可关注1.1、1.2、2.1、2.2部分,技术研究/实践者建议重点阅读1.3、1.4、2.3部分。
一、精粹导览
1.1 观点
目前Google主推“CSP严格模式”,它指包含“nonce-”指令的CSP规则,实践证明能有效阻断(Mitigate)反射、存储型XSS。 虽然XSS仍是业界广泛面临的安全风险,但通过启用“CSP严格模式”,Google的初战告捷,XSS阻断效果得到令人振奋的数据支撑。 因涉及大量代码重构,部署往往无法“一锤定音”。根据Google实践经验,可通过“strict-dynamic”、“script-src-attr”等指令键过渡,最终向”CSP最严格模式(仅启用nonce指令)“收拢。
1.2 数据
解决痛点:2014年至今,XSS约占Google奖励计划(Google VRP)确认漏洞的75%,仍是“头号公敌”。 部署广泛:Google约62%出流量、超过80个子域名及160多个服务,已启用CSP严格模式。 效果显著:约60%的XSS外部报告,在进一步利用前,成功被CSP阻断。核心域名下,收敛约80%的已知XSS攻击。
1.3 实践
广泛应用含nonce指令的“严格模式”CSP,弃用纯依赖域名白名单且开启“unsafe-inline”的“CSP宽松模式”。 CSP部署过程中,不断推动JS代码重构。移除代码中不安全的内联事件、eval()类方法,进一步收敛攻击面。 遵守规范安全开发、及时修复漏洞仍是“第一要务”。CSP作为纵深防护方案,在业务上线后,“兜底”阻断XSS的利用。但不能因此不修复漏洞。
1.4 动向
新增4个指令键,建议关注script-src-attr。根据CSP最新W3C规范,新加入了script-src-elem、script-src-attr、style-src-elem及style-src-attr四条指令键。其中,script-src-attr允许不移除on事件属性或javascript伪协议的情况下,通过sha256-指令阻断不可信脚本执行,降低部署CSP严格模式的改造成本。目前,Chrome 75及以上版本已率先支持。
二、知识背景
CSP的原理是,浏览器客户端以指令键形式(如:script-src),向Web开发者开放页面资源管控能力。通过编写CSP规则,可以构建“前端沙箱”,保证页面渲染结束时都是预期的内容。最终实现“敏感信息带不出去,恶意资源跑不起来”的防护效果。
近年来,围绕“增强阻断效果”、“降低部署成本”两个目标,CSP规范不断优化演进。最早制订的一代标准(CSP1)和最新的三代标准(CSP3)有很大不同,提供的防护能力也有天壤之别。两者差别,可类比为移动通讯中的“2G”与“5G“。
为便于理解,下文涉及的基础概念阐释如下:
[1] CSP规则。是由一系列键和值对组成的HTTP响应头。“键”指定要管控的资源类型,例如,script-src可控制页面所有JS脚本的行为。“值”包含“CSP指令”,用来指定白名单逻辑。例如,'unsafe-inline'表示允许执行内联脚本。
图2-0-1:CSP规则的组成说明
[2] CSP严格模式。自CSP二代标准(CSP2)引入的概念,可根据是否包含'nonce-'指令辨识,是Google等厂商主推的最佳实践方案。除非有特殊说明,下文所提CSP默认均指“CSP严格模式”。下图是一个“CSP严格模式”的典型案例:
图2-0-2:“CSP严格模式”典型案例(bugly.qq.com)
受篇幅限制,更多CSP技术细节可参考最新W3C规范及MDN:
Content Security Policy Level 3www.w3.orgContent Security Policy (CSP)developer.mozilla.org
3.1 背景:为什么要广泛部署CSP?
一开始,Google团队就”用数据说话“。一方面,公开自家VRP Program(漏洞奖励计划)数据,现身说法,XSS类风险占所有历史确认漏洞的75%。另一方面,引用Hackerone、Mozilla的数据,揭示XSS数量占“压倒性”比重,进一步佐证了风险的广泛性。
图 3-1-1:Google漏洞奖励计划确认漏洞类型分布
这部分指出,XSS形式多样、利用灵活,仍是Google乃至整个行业面临的首要安全风险,需要重点关注。对于核心业务,例如涉及账密、用户活动记录等隐私的敏感服务,类似CSP的“纵深防护(Defense-in-Depth)”措施,应作为首要兜底方案部署,以减轻安全函数库过滤缺失/失效时,产品面临的风险。
同时还阐明了一个认知误区,漏洞缓解措施(Mitigation)应以“彻底收敛攻击面,根本地解决漏洞”为导向,而不单是为了提高利用难度,由此带来的益处,不言而喻。比如,严格模式CSP可以使所有通过eval()或javascript:执行的XSS失效。但纯基于白名单的CSP,通过查找jsonp接口等方式,攻击者成功利用XSS,只是时间问题。
最后,这部分还提到部署CSP的过程,也是代码加固、重构的过程,会有一定成本。具体来说,涉及重构移除内联事件,eval()类方法,以及使用能依据场景自动添加nonce属性的模版系统。
3.2 绝非“纸上谈兵”:部署CSP获得显著收益
本节主要介绍了Google业务的CSP覆盖度现状,通过对2018年Google XSS漏洞报告的复盘,直观地呈现真实收益。给因顾虑有成本、收益不明朗,而对部署CSP犹豫不决的人们,打了一剂“强心针”。
在Google,CSP整体已取得较高覆盖度。“严格模式CSP”,正为62%的业务出流量提供保障。其中包括,80多个Google子域名,及超过160项业务。
**图3-2-0:**典型业务案例
实战效果方面, 团队围绕2018全年漏洞报告数据,对CSP的收益进行了复盘。涉及核心域名的XSS漏洞报告共11例。其中9例业务已部署CSP,7例被成功阻断。报告者仅能论证代码存在缺陷,但无法在真实场景下产生危害,有效率约为78%。涉及敏感业务的XSS共69例,20例已部署严格模式CSP,成功阻断12例产生实际风险,有效率约为60%。
图3-2-1:“CSP严格模式”对已知XSS的阻断效果显著
团队分析了报告的XSS利用手法,包括注入恶意HTML标签(占29%)、javascript:伪协议(占23.2%)、 innerHTML写入(占8.7%)等。但绝大部分利用方法在正确配置CSP规则后,能被成功阻断。
图3-2-2:针对不同XSS利用方式,CSP阻断的生效条件
以Google核心域名为例,2018年外部发现且未被阻断的4例XSS,50%由于未部署CSP、完全无防护,剩余50%可通过优化CSP规则解决。换句话说,调整后,CSP可100%覆盖上述11例已知的XSS攻击。
图3-2-3:Google核心域名CSP未成功阻断案例复盘
3.3 CSP实践经验
当前,Google广泛部署的是包含nonce指令的”CSP严格模式“。nonce类似一个“接头暗号”,不可预测且页面刷新时会变化,只有当HTTP头和HTML属性值相等时,特定脚本才能执行。由于攻击者无法预知有效nonce值,插入的恶意代码因而不能执行。
而仅启用CSP1特性、类似如下的实践,有很多绕过方式。比如,仅使用了'unsafe-inline',而未引入'nonce-xxx',这样的Payload仍能生效。已被强烈建议弃用:
script-src 'unsafe-inline' 'self' https://www.google.com;
Google将CSP严格模式,按部署成本和攻击面收敛效果,又细分为L1-5个级别。对常见反射、存储型XSS均有阻断效果。区别在于,随L1-5中数字的升高,部署涉及的代码改造成本和绕过的难度,由易到难、由宽到严。用一图概括如下:
图3-3-1:Google划分的4个“CSP严格模式”的子级别
使用了上述“CSP严格模式”细分级别的真实业务,示例如下:
L2 "nonce-" + "strict-dynamic" + "unsafe-eval"
示例: https://wx.mail.qq.com Content-Security-Policy: script-src 'self' https://.http://oa.com https://hm.baidu.comhttp://hm.baidu.com .http://google-analytics.com http://mat1.gtimg.comhttps://mat1.gtimg.com http://.http://soso.com https://.http://soso.com http://.http://qq.com https://.http://qq.com http://.http://qqmail.com https://.http://qqmail.com http://pub.idqqimg.com 'nonce-14540bb353ac024b89bb712b2e42cb28' 'unsafe-eval';
L3 "nonce-" + "strict-dynamic"
示例: https://source.cloud.google.com script-src 'report-sample' 'nonce-dbPi3E/iWghf7q0wg5k1Kw' 'unsafe-inline' 'strict-dynamic' https: http:;object-src 'none';base-uri 'self';report-uri /_/cspreport
L4/5 纯"nonce-"或"nonce-"+域名白名单
示例: https://bugly.qq.com Content-Security-Policy: default-src 'self' .http://qq.com report.url.cn; script-src 'self' 'nonce-YmUxZjBiNTIwOTYxMjkxYzFmYjhiM2NiNTQ0NGJlZTRhZjAwNWYyYTE1NTg0NjE1NzU4OTQuMTUzODE=' .http://qq.com .http://oa.com https://pub.idqqimg.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline' ; img-src 'self' .http://qq.com .http://oa.com .http://qlogo.cn http://report.url.cn https://www.google-analytics.com http://mp.weixin.qq.com data: ; report-uri https://aq.qq.com/cn2/manage/mbtoken/hijack_csp_report
各级“CSP严格模式”,针对不同XSS利用方式的防护能力,比对如下:
图3-3-2:不同级别的“CSP严格模式”比对
3.4 进阶:“高级”CSP技术
本部分标题议题原文用的“Advanced CSP Techniques”,翻译过来就是“高级CSP技术”。其实,所谓“高级技术”并不神秘,包含两点:CSP3引入的新指令、多CSP头(Double Policy)部署。
议题先讨论了CSP3引入的新指令。通过实践“反补”理论,最新CSP3规范引入了4条新指令(2018年的议题就有涉及)。用于降低CSP部署的代码重构成本,并进一步细化浏览器提供的资源管控能力。新指令分别有:
script-src-elem,用于控制script标签,用法与原有的script-src几乎一致 script-src-attr,用于控制内联事件属性(如:onclick) style-src-elem,用于控制style标签,用法与原有的style-src几乎一致 style-src-attr,用于控制style属性
其中最值得注意的是script-src-attr指令,它降低了JS代码重构相关的部署门槛。配合script-src-elem使用,能让开发者在不移除内联事件属性的情况下,启用nonce。
如下图所述,"unsafe-hashes"表示允许使用onclick='' / javascript:void(0)这样的内联JS代码,但前提是页面内联脚本的sha256哈希值与白名单定义的值相互匹配。
图3-4-1:script-src-attr指令键原理解读
具体来讲,'sha256-jE1Jw...'表示允许执行"javascript:void(0)",'sha256-rRMdk...'表示允许执行onclick="alert('clicked')"。即,只有当位置2脚本内容的sha256值与在位置1处定义的相匹配时,才能被执行。如果攻击者注入,因为alert('x')的sha256值不在白名单,故恶意代码无法执行,XSS被阻断。
议题还介绍了**“双指令(Double Policy)”**的概念。所谓“双指令”,其实就是同时组合使用CSP1中域名白名单和CSP2中nonce两个特性。根据RFC2616定义,一条CSP规则中的可设置多个相同名称的指令键,会同时生效,例如:script-src 'self', script-src 'nonce-r4nd0m';。
Google不少业务目前都使用了该特性。例如,Gmail设置的CSP规则:
图3-4-2:Gmail使用“双指令”设置的CSP
3.5 One More Thing
本部分主要探讨了两点:
推荐启用'report-sample',上报被CSP拦截的JS代码样本,有助于定位误报。当前仅Chrome、Opera浏览器支持,效果如下:
图3-5-1:report-sample指令示例
探讨了当多个指令同时出现时,不同浏览器的取舍逻辑。
四、总结
本文观点与建议,总结如下:
XSS细分种类众多,发生率高,场景复杂,仍是全行业亟需攻克的“顽疾”。 XSS的解决方案可不仅拘泥于扫描,行业主推的纵深防护方案CSP已趋近成熟,显著的实践收益为难题收敛带来一线希望,非常值得一试。 含nonce指令的“CSP严格模式”是W3C最新规范定义的“最佳实践方式”,其效果也经Google的实践验证。仍在单纯使用CSP一代标准的站点,应尽早做改造升级,以获得最强的防御能力。 部署“CSP严格模式”有一定成本,但并非“遥不可及”。Google和腾讯实践经验都显示,通过循序渐进的改造,最终能在业务中落地“CSP严格模式”,并获得可观的防护效果。 安全规范地开发、及时修复漏洞仍非常重要。
附:对应关系参考
最后
欢迎加我微信(winty230),拉你进技术群,长期交流学习...
欢迎关注「前端Q」,认真学前端,做个专业的技术人...