好消息!大家期待已久的一个项目终于落地了:Report URI正式启用基于一次性随机数(nonce)的内容安全(Content Security Policy,CSP)策略。
内容安全策略
大家应该都很熟悉内容安全策略了。CSP提供了一站式解决方案,用以抵御包括跨站点脚本(Cross-Site Scripting,XSS)在内的各类应用程序攻击。虽然近年来使用CSP,特别是CSP随机数,可能身陷侵权风险,但CSP无疑是一项伟大的技术。你可以用2015年推出的Report URI工具生成风险报告,甚至通过Script Watch和Data Watch来防范Magecart等现代网络攻击。本文主要聚焦CSP的全新特性。
CSP主机白名单
CSP的常见操作之一就是维护资源加载源头主机的白名单。例如,使用script-src指令:
script-src 'self' 'report-sample' disqus.com c.disquscdn.com platform.instagram.com cdnjs.cloudflare.com scotthelme.disqus.com a.disquscdn.com go.disqus.com platform.twitter.com cdn.syndication.twimg.com syndication.twitter.com gist.github.com/ScottHelme/ static.cloudflareinsights.com js.stripe.com https://unpkg.com/@tryghost/;
在这个例子中,脚本来源不多,相对简单。但随着应用程序日益复杂,白名单管理将涉及添加新条目和删除旧条目,操作更为繁琐。鉴于存在诸多自托管资产,Report URI使用的白名单较为简单,如下所示:
script-src cdn.report-uri.com api.stripe.com js.stripe.com static.cloudflareinsights.com;
看似简单,CSP却行之有效。正因CSP禁止执行内联脚本,去年的年度渗透测试中,测试人员才无法利用XSS漏洞进行网络攻击,CSP从而有力地保护了系统。
CSP一次性随机数
如要使用内联JavaScript脚本,CSP可能略有不便。这时可以通过CSP一次性随机数进行JavaScript脚本加载。这种方式要求使用Cloudflare Worker来注入安全标头(Security Headers)。我之前的一篇博客曾详细介绍了如何通过Cloudflare Worker使用CSP随机数。当时我用的是报告模式(Content-Security-Report-Only)标头来设置和测试随机数,这种方式可以保障安全,即使有所纰漏,也不会造成问题。
尽管去年多次延期,经过大量测试之后终于达成目标,成功部署了基于CSP一次性随机数的强制策略。
欢迎访问Report URI网站或查看我们提供的安全标头扫描结果来验证这一策略。您也可以直接在开发工具或任意浏览器的源代码窗口中查看策略是否生效。
随机数与主机并重
我们同时使用了主机白名单和CSP随机数。尽管主机白名单简单,易于维护,基于一些考量我们仍选择同时使用CSP随机数。CSP规范如下:
无论内联脚本或外部脚本,具备正确随机数的脚本元素即可执行。如不具备正确随机数,URL在白名单之中的脚本元素才可执行。因此,即便能够将标记注入受保护的资源,如攻击者无法猜中随机值,攻击仍会失败。
这一机制足以抵御以下四种潜在风险场景:
- 攻击者注入不带随机数的内联脚本标签:因CSP禁止执行内联脚本,不会执行带此标签的脚本。
- 攻击者注入带有随机数的内联脚本标签:因攻击者无法猜中随机值,不会执行脚本。
- 攻击者注入不带随机数的外部脚本标签:因脚本来源不在白名单中,不会执行脚本。
- 攻击者注入带有随机数的外部脚本标签:因攻击者无法猜中随机值,不会执行脚本。
综上,主机白名单与CSP随机数并重的机制为系统提供了强有力的保护。下一步,我们要将script-src中的随机数分离到一个单独的CSP标头中,如下所示:
Content-Security-Policy: script-src cdn.report-uri.com api.stripe.com js.stripe.com static.cloudflareinsights.com;
Content-Security-Policy: script-src 'nonce-abc123'
目前,攻击者仅需要猜到CSP随机数值或使用白名单主机即可进行攻击。但当主机白名单和随机数位于不同标头中时,想要加载资源则需同时满足两种策略要求:来源是白名单主机且随机数正确。
强制策略层层加码意味着进一步限定了受保护的资源。
稿件来源:Report URI is now using CSP nonces in an enforced policy