来自 Cloudflare CDN 的链接 jQuery 脚本在 "sub-include" 下划线-min.js 的控制台中抛出 CSP 错误

Linked jQuery script from Cloudflare CDN throws CSP error in console on "sub-include" underscore-min.js

目前我有:

<script rel="preload" as="script" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>

我已经设置了 CSP 规则:

add_header Content-Security-Policy: "default-src 'self' https:; script-src 'self' 'sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=';";

但我在 Chrome 控制台中收到以下错误:

Refused to load the script 'https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js' because it violates the following Content Security Policy directive: "script-src 'self' 'sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8='". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

我该如何解决这个问题?我是否需要在我的 html 文档中明确包含 underscore-min.js(以及任何其他 "sub-included" 依赖项)?我可以将来自 cdnjs.cloudflare.com 的所有脚本列入白名单吗?

谢谢!

编辑: 这是 jquery.min.js 文件中出现的控制台错误的屏幕截图。

此外,不确定这是否相关,但我得到 Unrecognized Content-Security-Policy directive ':' 的 https: 规则的一部分,我在一些 Google devtools 文章或其他地方找到。但是我猜冒号对于nginx中的CSP规则是无效的?

编辑 2: 好吧,经过更多的研究和实验,我对 CSP 有了更多的了解,从我读到的内容来看,我可能遇到了一个仅限 FireFox 的问题。我现在收到以下错误,即使没有定义 CSP 规则:

Content Security Policy: Ignoring “'unsafe-inline'” within script-src: ‘strict-dynamic’ specified

我最接近可行的解决方案是将我需要从中加载的所有域列入白名单:

add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://stackpath.bootstrapcdn.com https://ssl.google-analytics.com https://www.google.com https://www.gstatic.com; img-src 'self' data: https://ssl.google-analytics.com; style-src 'self' 'unsafe-inline' https://stackpath.bootstrapcdn.com https://fonts.googleapis.com; font-src 'self' https://themes.googleusercontent.com; frame-src https://www.google.com; object-src 'none';";

是的,我知道我的 script-srcstyle-src 规则中都有 'unsafe-inline',试图让网站在 FireFox 中运行。如果网站由于 FF 的 CSP 实现的错误(需要确认)而不再在 FireFox 中呈现或正常运行,那么 CSP 的目的是次要的,因此是无关紧要的(直到这个等待确认的错误被修复)。

由于在撰写本文时似乎关于 CSP 的信息相对有限,任何人都可以阐明为什么 FireFox 似乎强制 'strict-dynamic' 进入 CSP 规则,尽管它没有出现在任何地方规则定义? FireFox 对我当前 CSP 规则(的部分)的解释是否暗示或以其他方式附加?

感谢您的帮助。

对于阅读 CSP 的任何其他人,请查看 https://cspvalidator.org/,它可以帮助您调试自己的 CSP 规则。我知道它对我有帮助!

对于任何未解决的潜伏者,我已将问题与 FireFox 当前处理 rel="preload" 属性的方式隔离开来。至少可以说它玩起来并不好,我认为 Edge 也是如此。

TL;DR: 不要使用 rel="preload",直到它在主要浏览器中得到更统一的处理。此外,我的问题是使用 CloudFlare CDN 中的 jQuery,CDN 的目的是防止访问者(毫无意义地)一遍又一遍地下载相同的内容。换句话说,rel="preload" 不仅在旗舰浏览器之间的行为不同,而且它变得多余,因为 CDN 的要点是访问者 已经下载了给定的文件 当访问以前的网站时也使用来自同一 CDN 的相同文件。

Click here 查看当前浏览器对 rel="preload" 的支持概览。


调查结果

Chrome 也许其他浏览器正在处理要正确预加载(更多)的资源,但总的来说我们似乎缺乏关于如何启动和 运行 CSP 正确,希望这个答案能给像我这样对 CSP 相对较新的其他人一些见解。

我在对 CSP 规则进行故障排除时发现了很多问题。其中之一是将 as 属性与 typehint 配对可能会对您使用 CSP 的当前浏览器实现不利。例如,我试图加载 as="font" 的 Google 字体,如果我没记错的话会导致额外的麻烦,直到它被设置为 as="style" 为止。我收集到的信息(如果您可以验证,请输入/编辑此答案)是因为链接的资源确实是样式表而不是字体文件。

我遇到的另一个奇怪的地方是,当你预加载资源时,你必须在加载后实际 'initialize' 给定的资源。因此,您的选择是使用所需的 rel="stylesheet/script/etc" 克隆 <link> 元素(这与 DRY 原则直接相反),或者将 onload 事件附加到 <link> 元素(这不反对 DRY,但 确实 感觉很陈旧。现在是 2019 年了!为什么我们的浏览器不能为我们做这件事?或者我们可以添加浏览器对类似 append="true" 属性会自动 优雅地 为我们处理这个问题。

我将从 the following GitHub project 中提取以下段落和代码片段,以更好地解释 onload“解决方案”( 在 FireFox 中工作,由于我在这个问题中记录的 CSP 错误):

In browsers that support it, the rel=preload attribute will cause the browser to fetch the stylesheet, but it will not apply the CSS once it is loaded (it merely fetches it). To address this, we recommend using an onload attribute on the link that will apply the CSS when it finishes loading.

<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">

如前所述,这感觉非常陈旧。我们不应该在冗余代码和陈旧代码之间做出选择。

我提到 Chrome 似乎有更好的 CSP 生产实现,但仍有一些工作要做。此外,我结束这个疯狂的 -hunt 的原因(自然地)是我正在努力提高网站的速度和性能,所以我使用了 Chrome Inspector 的 Lightouse / Audit 工具。好吧,从我进行的所有测试来看,似乎我们应该期望已经缓存在客户端计算机上的资源(Bootstrap、jQuery、Google 字体等)已被清除在执行审计之前重新下载并在生成的报告中说明。这很好(我理解这是期望的行为);但是,如果我们作为开发人员使用单选框 覆盖 在执行审核时通过 CDN 清除共享资源,我相信开发人员会对他们网站的性能有更高层次的洞察力。或者至少在报告中进行区分以准确显示下载和初始化链接资源所花费的时间。

这些依赖性不止于 rel="preload"。当我进行故障排除时,我在某些情况下尝试了替代值,例如 rel="connect" 我链接到通过 CloudFlare 的 CDN 提供的第一个资源。在对该主题进行研究时,我发现 the following article 具有以下信息:

The final resource hint we want to talk about is preconnect. Preconnect allows the browser to setup early connections before an HTTP request is actually sent to the server. This includes DNS lookups, TLS negotiations, TCP handshakes. This in turn eliminates roundtrip latency and saves time for users.

“Preconnect is an important tool in your optimization toolbox… it can eliminate many costly roundtrips from your request path - in some cases reducing the request latency by hundreds and even thousands of milliseconds. - Ilya Grigorik”

但是,不出所料,preconnect 在不支持 preload 的浏览器中表现相似。当您认为问题出在您的 CSP 规则而不是您的标记时,很容易将这一切搞混。

我希望这提供了一些背景信息,并有助于减轻一些关于 CSP 以及目前(缺乏)在主要浏览器中正确实施它的挫败感。请随时编辑此答案以改进它或添加更多上下文和信息以使我们的开发人员受益。