摘要

  • W3C 于 2011 年 11 月 29 日发布首份内容安全策略公开草案,提出由网站声明可以从哪里加载资源,由浏览器执行检查。
  • 2016 年 12 月 15 日的第二级正式建议写明强制策略与“仅报告”模式,也为特定内联脚本提供随机令牌和哈希识别方式。名单归网站写,门归浏览器守。

网站办了场宴会,却把请帖簿弄丢了。一个脚本来自熟悉的供应商,一个来自多年前装上去、如今无人认领的小组件。图片和字体排在门口,远处还有连接请求赶来。混进来的恶意代码只要挤进队伍,就想装作老朋友。此时请门卫当然容易;难的是主人能不能说清谁该进门。

W3C 2011 年 11 月 29 日的内容安全策略首份公开工作草案把这份工作分给了两方。草案描述一种声明式策略,让网站限制网页资源的加载来源,以减少包括跨站脚本在内的内容注入风险。网站先声明接受哪些来源。浏览器真正遇到加载请求时,再按规则检查。这不是在网页上挂一句“本站安全”,而是把每次资源请求交给一道可执行的门禁。

门禁也不是一张笼统的好人名单。早期草案列出 default-src、script-src、img-src、style-src、font-src、connect-src 等指令。图片可以从一组地址来,能执行的脚本却只准从更窄的范围进。挂在墙上的风景照与操纵灯光台的人承担不同工作,发同一张通行证毫无道理。CSP 让网站按资源类型说明自己的选择。

这套办法同时把网站逼到了镜子前。编辑和开发团队知道自己打算使用什么,浏览器看见网页实际请求了什么。策略把这两份记录接起来。写下 script-src 只要几秒钟;弄清十年前的促销页是否还靠某个外部脚本运行,可能要翻半天旧账。名单漏了支付组件,门卫会和拦住可疑脚本一样认真地拦住结账按钮。被挡住的正常功能暴露的是主人的名单管理问题。

W3C 于 2016 年 12 月 15 日发布的内容安全策略第二级正式建议给门卫安排了试岗。服务器发出 Content-Security-Policy-Report-Only 响应头时,浏览器会记录拟定策略的违规情况,让资源照常加载。标准文本用这个模式说明如何先观察、再把规则写进真正执行的 Content-Security-Policy 响应头。门卫先拿着本子数来客,熟悉了队伍,才拉起绳子。

这些报告不只是“疑似坏人”的名单。它们可能指向一套被遗忘的字体服务、一条旧网页上的统计连接,或者某个刚改过地址的必需组件。浏览器报告自己看到了什么;网站决定该移除资源、认可这个依赖,还是修正页面。观测模式最有价值的地方,是让网站看见自己真实运行的样子,而不是会议室白板上那个整齐的版本。

名单贴在什么位置也有差别。2016 年文本首选 HTTP 响应头,因为浏览器在处理页面之初便能拿到策略。HTML 的 meta 元素也能提供部分策略,但它管不到自己出现之前已加载的资源,而且不能承担“仅报告”模式。观众已经进了剧场才在大厅挂入场规则,最多能管迟到的人。响应头把规则送到了开门那一刻。

最棘手的客人是写在页面里的脚本。网站可能确实需要几段内联代码;一概允许所有内联脚本,又等于给注入的代码递请帖。第二级文本用随机令牌和哈希提供更细的邀请方式。服务器为一次响应生成随机值,让策略和获准脚本持有相配的令牌;哈希则对应一段脚本的确切内容。这样,网页能点名某位客人,门卫不用见到 JavaScript 字样就放行。

门也不止一扇。img-src 管图片,connect-src 管某些网络连接,base-uri 管相对链接的基准地址,form-action 管表单提交目的地,frame-ancestors 管谁能把这个网站装进自己的页面框架。每条规则对应不同动作。网站写意图,浏览器在动作发生时核对,网站再从报告和页面表现中知道名单写得怎样。

W3C 的 CSP 第二级出版记录把 2016 年正式建议放在此前一系列草案之后。这些日期标记的是标准文本。历史上真正留下来的分工更有意思:网站终于能给浏览器一份可执行的来客名单,浏览器能在每次加载时查验,而“仅报告”机制让网站先发现自己的家里究竟住着谁。

读者打开新闻、登录账户或付款时,通常不会先读响应头。他们只会发现页面是否好用,或某个组件为什么突然没了声息。CSP 做的是幕后工作。浏览器可以把没拿到请帖的脚本挡在门外;网站必须先把请帖写清楚。科技进步有时很像一次尴尬的点名。