使用 'strict-dynamic' CSP 指令加载脚本的正确方法是什么?
What is the correct way to load a script with the 'strict-dynamic' CSP directive?
背景
Content Security Policy 的想法是告诉网络浏览器从哪里加载什么内容。这意味着如果 'unsafe-inline'
没有被明确允许(这不是最好的做法),攻击者就不能注入他们自己的代码。
Google还发布了一个CSP Evaluator,旨在发现您的策略中可能存在的错误。在默认设置下,该工具建议对 'script-src'
使用 'strict-dynamic'
策略。它背后的想法是,你为你需要的任何 JavaScript 来源编写一个加载程序,并禁止其他所有内容。
问题
实现这种加载器的 "correct" 方法是什么?应该自己编写加载程序(参见下面的示例)还是应该使用工具来创建这样的加载程序? (请注意,此问题不是要求具体的工具推荐)
例子
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 的工具建议如下:
Host whitelists can frequently be bypassed. Consider using 'strict-dynamic'
in combination with CSP nonces or hashes.
因此,我想实现一个加载器来加载这些 JS 框架,我想知道如何最好地解决这个问题。
一个直接的答案是,只要您动态加载的脚本 (/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
),攻击者可以利用它来将 HTML 注入转换为任意脚本执行(here 是一篇论文对这个)。
CSP 评估器工具中的建议是将您的应用程序切换为依赖 script-src
,它使用 CSP 随机数而不是白名单。为此,您需要遵循 https://csp.withgoogle.com/docs/strict-csp.html -- basically, make sure that every <script>
element has a correct nonce
attribute which changes for every page load, or instead use CSP3 hashes 中针对静态脚本列出的流程。
您的 CSP 将如下所示:
... script-src 'nonce-[random-value]' 'strict-dynamic' 'unsafe-inline' https:; ...
如果您使用 'strict-dynamic'
,您的脚本加载器不必更改,因为浏览器会自动信任通过 appendChild()
.
等编程 API 添加到您页面的脚本
背景
Content Security Policy 的想法是告诉网络浏览器从哪里加载什么内容。这意味着如果 'unsafe-inline'
没有被明确允许(这不是最好的做法),攻击者就不能注入他们自己的代码。
Google还发布了一个CSP Evaluator,旨在发现您的策略中可能存在的错误。在默认设置下,该工具建议对 'script-src'
使用 'strict-dynamic'
策略。它背后的想法是,你为你需要的任何 JavaScript 来源编写一个加载程序,并禁止其他所有内容。
问题
实现这种加载器的 "correct" 方法是什么?应该自己编写加载程序(参见下面的示例)还是应该使用工具来创建这样的加载程序? (请注意,此问题不是要求具体的工具推荐)
例子
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 的工具建议如下:
Host whitelists can frequently be bypassed. Consider using
'strict-dynamic'
in combination with CSP nonces or hashes.
因此,我想实现一个加载器来加载这些 JS 框架,我想知道如何最好地解决这个问题。
一个直接的答案是,只要您动态加载的脚本 (/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
),攻击者可以利用它来将 HTML 注入转换为任意脚本执行(here 是一篇论文对这个)。
CSP 评估器工具中的建议是将您的应用程序切换为依赖 script-src
,它使用 CSP 随机数而不是白名单。为此,您需要遵循 https://csp.withgoogle.com/docs/strict-csp.html -- basically, make sure that every <script>
element has a correct nonce
attribute which changes for every page load, or instead use CSP3 hashes 中针对静态脚本列出的流程。
您的 CSP 将如下所示:
... script-src 'nonce-[random-value]' 'strict-dynamic' 'unsafe-inline' https:; ...
如果您使用 'strict-dynamic'
,您的脚本加载器不必更改,因为浏览器会自动信任通过 appendChild()
.