用“严格动态” CSP指令加载脚本的正确方法是什么?

时间:2018-06-25 13:32:13

标签: javascript content-security-policy

背景

Content Security Policy的想法是告诉网络浏览器要从何处加载哪些内容。这意味着,例如,如果未明确允许'unsafe-inline'(这不是最好的做法),攻击者将无法注入自己的代码。

Google还发布了CSP Evaluator,旨在发现您的政策中可能存在的错误。使用默认设置,该工具建议对'strict-dynamic'使用'script-src'策略。其背后的想法是,您为所需的任何JavaScript源编写一个加载器,并禁止其他所有内容。

问题

什么是实现这种加载程序的“正确”方法?应该使用自己编写加载程序(例如,参见下文)还是应该使用工具来创建这样的加载程序? (请注意,此问题并非要求提供具体的工具建议)

示例

var imported = document.createElement('script');
imported.src = '/path/to/imported/script';
document.head.appendChild(imported);

上下文

我的网站目前具有以下政策:

default-src 'none';
img-src 'self';
style-src 'self' https://stackpath.bootstrapcdn.com 'sha256-bviLPwiqrYk7TOtr5i2eb7I5exfGcGEvVuxmITyg//c=';
script-src https://use.fontawesome.com https://code.jquery.com https://cdnjs.cloudflare.com https://stackpath.bootstrapcdn.com;
base-uri 'none';
form-action 'none';
frame-ancestors 'none';

Google的工具建议如下:

  

主机白名单可以经常被绕开。考虑将'strict-dynamic'与CSP随机数或哈希值结合使用。

这样,我想实现一个加载器来加载这些JS框架,并且我想知道如何最好地解决这个问题。

1 个答案:

答案 0 :(得分:2)

一个直接的答案是,只要您正在动态加载的脚本(/path/to/imported/script)托管在您已经在script-src中列入白名单的域中,就无需修改您的CSP或更改加载程序-一切都会按预期进行。

但是,更广泛的问题是您的script-src白名单中包含托管Javascript的域,攻击者可以在应用程序中发现标记注入错误以绕过CSP来使用这些域。例如,https://cdnjs.cloudflare.com托管了Angular(https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.2/angular.min.js),攻击者可以使用Angular将HTML注入转换为任意脚本执行(here是有关此问题的论文)。

CSP评估程序工具中的建议是将您的应用程序切换为依赖于script-src,该{@ 1}使用CSP随机数而不是白名单。为此,您需要遵循https://csp.withgoogle.com/docs/strict-csp.html中概述的过程-基本上,请确保每个<script>元素都具有正确的nonce属性,该属性随每次页面加载而变化,或者使用CSP3 hashes用于静态脚本。

您的CSP如下所示:

... script-src 'nonce-[random-value]' 'strict-dynamic' 'unsafe-inline' https:; ...

如果您使用'strict-dynamic',则不必更改脚本加载器,因为浏览器将自动信任通过编程API(例如appendChild())添加到页面的脚本。