内容安全策略与你的CMP:让CSP与同意协同工作

必须保持一致的两层安全机制

内容安全策略(CSP)告诉浏览器,页面可以从哪些来源加载脚本、样式、图像、框架和网络请求。同意管理平台则做相反的工作:根据用户的选择,决定这些脚本中哪些可以运行。当二者被分别配置时,就会发生冲突。要么CMP因被CSP阻止而无法加载,要么为了迁就CMP和广告标签而将CSP放得太宽,以至于它什么也保护不了。

本指南说明CMP通常需要哪些CSP指令、nonce如何与脚本注入相互作用,以及如何在不破坏横幅的前提下推出变更。

CMP通常需要CSP提供什么

具体要求因供应商而异,因此请始终从你的CMP自己的文档入手。一般来说,请检查这些指令:

在TCF网站上,请记住CMP还会在页面上创建一个名为__tcfapiLocator的定位器框架。该框架创建时没有远程来源,因此通常不需要frame-src条目,但值得在测试中确认。

内联存根问题

大多数CMP会要求你在页面头部放置一小段内联脚本——即存根——以便其他脚本在主CMP加载之前将调用排入队列。严格的CSP会阻止内联脚本,除非你明确允许。你有三种选择:

  1. nonce。为每个响应生成一个随机值,作为'nonce-...'添加到CSP头中,并添加到存根的<script>标签上。这是动态页面最灵活的选择。
  2. 哈希。将存根确切内容的SHA-256哈希添加到script-src。这对静态网站很有效,但对存根的任何改动,哪怕只是空白字符,都会使其失效。
  3. 自托管存根,作为你自己域名上的外部文件,由'self'覆盖。这需要注意确保它加载得足够早。

不要为图省事使用'unsafe-inline'。它会允许所有内联脚本,从而消除CSP所提供的大部分保护。

nonce与CMP注入的脚本

在获得同意之前阻止脚本的CMP,通常的做法是先扣留脚本,之后再注入。在基于nonce的CSP下,这些被注入的脚本也需要被允许。有两种常见做法:

标签管理器也会引出同样的问题。如果你通过标签管理器加载广告和分析标签,请遵循其关于nonce的文档,并确保CMP和标签管理器采用一致的方法。

广告标签让CSP更难

程序化广告会从许多域名加载脚本和框架,而且该列表会随需求合作伙伴的变化而变化。发布商通常会做出两种选择之一:

无论哪种方式,CMP都应出现在明确的允许列表中,而不是仅由通配符覆盖,这样CSP的变更就不会悄悄使横幅失效。

使用Report-Only模式推出

首先使用Content-Security-Policy-Report-Only头。浏览器会报告违规而不阻止任何内容,这样你就能看到新策略会破坏什么。

  1. 以report-only模式部署策略,并配置报告端点。
  2. 在干净的浏览器配置文件中加载页面,并走完完整的同意流程:首次访问、全部接受、全部拒绝、自定义选择、撤回。
  3. 查看违规报告和浏览器控制台,找出被阻止的CMP资源。
  4. 调整策略,然后切换到强制执行。
  5. 强制执行后保持报告开启,以发现回归问题。

CSP冲突的症状

核心要点

← 博客 阅读全部 →