内联JavaScript与CSP 1级结合使用

Dyg*_*nus 5 javascript json inline http content-security-policy

关于使用内联JavaScript的思考

我们的开发团队正在开发一个新的Web相关项目.在这个项目中,安全性具有非常高的优先级.但是,在浏览器支持方面实施内容安全策略(CSP)变得非常痛苦和麻烦.

众所周知,CSP是通过阻止所有外部CSS/JavaScript文件并阻止内联脚本执行来引入缓解XSS注入的.指令允许我们定义浏览器将执行的内容和来源的白名单(例如,"自我",域,协议等).

然而,执行内联JavaScript代码是一个完全不同的故事.CSP确实允许使用'unsafe-inline'指令执行内联代码.但是,添加此指令会违背实现CSP的目的.

为了克服这个障碍,我们的团队花了一些时间讨论可行和可行的解决方案.在以下段落中,我们将讨论一些解决方案.欢迎对这些解决方案提出任何建议和反馈.

提案#1:外部文件

在外部文件中提供页面特定代码.此文件将在每个请求中生成,因为它包含动态数据(例如Google Maps密钥,GA跟踪代码段,php-debugbar).以下习语说明了如何在HTML代码中实现此提议.

<html>
    <head>
        <script src="/generated/external-file.js"></script>
    </head>
</html>
Run Code Online (Sandbox Code Playgroud)

优点:客户端将保持透明,因为服务器必须生成文件.

缺点: HTTP是无状态协议,随每个请求而变化的动态数据不能包含在外部文件中(例如php-debugbar).

提案#2:Nonce与CSP一起使用

CSP的第2级通过在CSP响应头中提供随机数来支持内联样式和脚本.下面的习惯用法说明了一个内联脚本,其nonce属性包含动态生成的值.

<script nonce="nm77q3oep8l0ybxmugzewkfyacyma3n3">console.log('Hello world');</script>
Run Code Online (Sandbox Code Playgroud)

为了执行此脚本,nonce需要出现在CSP响应头中.下面的习惯用法说明了如何将此随机数结合到响应头中.

Content-Security-Policy: script-src 'nonce-nm77q3oep8l0ybxmugzewkfyacyma3n3'
Run Code Online (Sandbox Code Playgroud)

出于安全原因,此随机数必须是随机的,并且必须在每个请求上重新生成.

优点:由CSP的第2级支持.

缺点:浏览器支持是一个问题(75%的浏览器实现CSP级别2,约会2017年4月10日(http://caniuse.com/#feat=contentsecuritypolicy2).

提案#3:与CSP一起进行哈希处理

CSP的第2级通过散列这些元素的内容并在CSP响应头中提供此哈希来支持内联样式和脚本.下面的习惯用法说明了一个内联脚本,其内容将生成以下SHA-256哈希值:9e8a3b5e27971b7309ff6c00f5c80644ffe8e635ce797d7eed8ee23d485a19f2

<script>console.log('Hello world');</script>
Run Code Online (Sandbox Code Playgroud)

为了执行此脚本,计算的哈希需要存在于CSP响应头中.以下习语说明了如何将此哈希合并到响应头中.

Content-Security-Policy: script-src 'sha256-9e8a3b5e27971b7309ff6c00f5c80644ffe8e635ce797d7eed8ee23d485a19f2;'
Run Code Online (Sandbox Code Playgroud)

优点:由CSP的第2级支持,并允许通过使用HTTP加速器来缓存页面.

缺点:浏览器支持是一个问题(75%的浏览器实现CSP级别2,约会2017年4月10日(http://caniuse.com/#feat=contentsecuritypolicy2).

提案#4:JSON

CSP仅禁止包含可执行JavaScript代码的脚本元素,简而言之,这意味着允许脚本元素中的配置数据.以下习语说明了包含JSON数据的脚本元素.

<script type="application/json">
{
    "googleMapsKey": "v1zs9Bc10hMZ073S14gy",
    "analyticsProperty": "UA-192348"
}
</script>
Run Code Online (Sandbox Code Playgroud)

有关更多信息和示例,请参阅https://mathiasbynens.be/notes/json-dom-csp.

优点:非常安全,因为它不允许脚本标记内的可执行代码.

缺点:此解决方案无法解决每个请求(例如php-debugbar)的动态生成的JavaScript代码.

提案#5:自定义nonce实现

实现自定义nonce解决方案,该解决方案可能会在大多数浏览器支持CSP级别2之前使用.以下内容说明了如何实现此解决方案.

请参阅JSFiddle代码(适用于工作)和Gist与原始代码.

为了执行此脚本,必须在响应头中提供'unsafe-eval'指令.虽然不建议这样做,但这种方法的支持.除了许多像Vue.js这样的框架需要指令才能工作.

以下习语说明了如何将指令合并到响应头中.

Content-Security-Policy: script-src 'unsafe-eval'
Run Code Online (Sandbox Code Playgroud)

优点:支持CSP级别1,当大多数浏览器支持CSP级别2时,可以适应提案#2而不会有太多麻烦.

缺点:自定义实现必须经过全面测试,并且在CSP头中需要"unsafe-eval"指令.

请分享你的,我们会评价任何反馈!

Roa*_*efs 0

内容安全策略可以逐页定义:您可以根据特定页面的特定需求微调特定页面的策略。

外部文件

我建议首先将所有“非动态”内联样式和脚本移至外部文件,而不是试图找到解决所有问题的解决方案。内容安全策略的存在是因为内联脚本并不总是可信。除了与 CSP 配合良好之外,使用外部文件还有许多优点:

  • 外部资源更容易被浏览器缓存;
  • 对于开发者来说更​​容易理解;
  • 有利于编译和缩小。

沙盒

另一个值得关注的“解决方案”是沙箱。如果sandbox存在该指令,则页面将被视为加载到<iframe>具有sandbox属性的内部。

有关沙箱的更多信息可以在: HTML5 规范中找到。

更多信息

Google 开发者指南:内容安全政策

Mozilla 开发人员指南:内容安全策略

W3C 的 Web 应用程序安全工作组已经开始制定该规范的下一个版本,即内容安全策略级别 3