Chrome 18+:如何使用内容安全政策允许内联脚本?

Chr*_*and 30 google-chrome google-chrome-extension content-security-policy

Chrome 18 Dev/Canary刚刚发布,并且content_security_policy在某些扩展的清单中将需要.

我正在尝试让CSP为内联脚本工作,但我不知道我做错了什么或者这是否是Chrome 18错误.

manifest.json的:

{
    "name": "CSP Test",
    "version": "1.0",
    "manifest_version": 2,
    "options_page": "test.html",
    "content_security_policy": "default-src 'unsafe-inline'"
}
Run Code Online (Sandbox Code Playgroud)

的test.html:

<html><head>
<script type="text/javascript">
        alert("hello");
</script>
</head></html>
Run Code Online (Sandbox Code Playgroud)

在Chrome 18中,此解压扩展无法加载,显示错误:

无法从'[扩展名目录]'加载扩展程序. 'content_security_policy'的值无效.

如果我更改'unsafe-inline''self',扩展加载正常,但alert()不起作用,并且选项页面的控制台包含错误:

由于Content-Security-Policy,拒绝执行内联脚本.

在Chrome 16中,使用'unsafe-inline'让扩展程序加载正常并且也能alert()正常工作.但是,在Chrome 16中,替换'unsafe-inline''foo'让扩展加载,但当然不会让alert()工作,所以也许Chrome 18比16更严格,但......

default-src 'unsafe-inline'居然无效,或者这是一个错误?我可以使用什么CSP值来alert()在Chrome 18中工作?


根据下面接受的答案,内联脚本不再适用于Chrome 18中的扩展程序.alert()需要将其放在自己的JavaScript文件中.

Chr*_*unt 24

对于最新版本的Chrome(46+),目前的答案已不再适用.unsafe-inline仍然没有效果(在清单和meta标头标签中),但根据文档,您可以使用此处描述的技术来放宽限制.

<script>元素的哈希用法

script-src指令允许开发人员通过将其哈希指定为允许的脚本源来将特定内联脚本列入白名单.

用法很简单.服务器计算特定脚本块内容的哈希值,并在Content-Security-Policy头中包含该值的base64编码:

Content-Security-Policy: default-src 'self';
                     script-src 'self' https://example.com 'sha256-base64 encoded hash'
Run Code Online (Sandbox Code Playgroud)

考虑以下:

manifest.json:

{
  "manifest_version": 2,
  "name": "csp test",
  "version": "1.0.0",
  "minimum_chrome_version": "46",
  "content_security_policy": "script-src 'self' 'sha256-WOdSzz11/3cpqOdrm89LBL2UPwEU9EhbDtMy2OciEhs='",
  "background": {
    "page": "background.html"
  }
}
Run Code Online (Sandbox Code Playgroud)

background.html:

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <script>alert('foo');</script>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

结果:
内联脚本的警告对话框

进一步的调查

我还测试了将适用的指令放在meta标签而不是清单中.虽然控制台消息中指示的CSP确实包含了标记的内容,但它不会执行内联脚本(在Chrome 53中).

新的background.html:

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'sha256-WOdSzz11/3cpqOdrm89LBL2UPwEU9EhbDtMy2OciEhs='">
  </head>
  <body>
    <script>alert('foo');</script>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

结果:
控制台有关内容安全策略的错误消息

附录:生成哈希

以下是生成哈希的两种方法:

  1. Python(将JS传递给stdin,将其传递到其他地方):
import hashlib
import base64
import sys

def hash(s):
    hash = hashlib.sha256(s.encode()).digest()
    encoded = base64.b64encode(hash)
    return encoded

contents = sys.stdin.read()
print(hash(contents))
Run Code Online (Sandbox Code Playgroud)
  1. 在JS中,使用Stanford Javascript加密库:
var sjcl = require('sjcl');
// Generate base64-encoded SHA256 for given string.
function hash(s) {
  var hashed = sjcl.hash.sha256.hash(s);
  return sjcl.codec.base64.fromBits(hashed);
}
Run Code Online (Sandbox Code Playgroud)

确保在对内联脚本进行散列时,包括脚本标记的全部内容(包括所有前导/尾随空格).如果你想将它合并到你的构建中,你可以使用像cheerio这样的东西来获得相关的部分.一般来说,对于任何人html,您可以这样做:

var $ = cheerio.load(html);
var csp_hashes = $('script')
  .map((i, el) => hash($(el).text())
  .toArray()
  .map(h => `'sha256-${h}'`)
  .join(' ');
var content_security_policy = `script-src 'self' 'unsafe-eval' ${csp_hashes}; object-src 'self'`;
Run Code Online (Sandbox Code Playgroud)

这是hash-csp中使用的方法,hash-csp是用于生成哈希的gulp插件.


Ste*_*ano 14

以下答案适用于旧版Chrome(<46).对于最近的,请查看@ Chris-Hunt回答/sf/answers/2698815381/

我刚刚发布了一个非常类似的问题/sf/answers/816922361/的答案

如前所述,没有办法放宽v2扩展中的内联安全策略.unsafe-inline故意无济于事.

除了将所有javascript移动到js文件中并指向它们之外,没有其他办法<script src>.

但是,可以选择在沙盒iframe中执行Eval和new Function,例如在清单中使用以下行:

"sandbox": {
    "pages": [
      "page1.html",
      "directory/page2.html"
    ]
},
Run Code Online (Sandbox Code Playgroud)

沙盒页面无法访问扩展或应用程序API,也无法直接访问非沙盒页面(它可以通过postMessage()与它们通信).您可以使用特定CSP进一步限制沙盒权限

现在,谷歌Chrome团队在iframe上的github eval上有一个关于如何通过与沙盒iframe通信来规避问题的完整示例,以及一个简短的分析教程

感谢Google,在阵容中有很多扩展名重写:(

编辑

可以放宽REMOTE脚本的安全策略.但不是为了内联.

针对该政策eval()及其亲属一样setTimeout(String),setInterval(String)以及new Function(String)可以通过添加适当放宽'unsafe-eval'到您的策略: "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"

但是,我们强烈建议不要这样做.这些函数是臭名昭着的XSS攻击向量.

这出现在主干文档中,并在线程"eval re-allowed"中讨论

inline scripts 不会回来:

没有放松对执行内联JavaScript的限制的机制.特别是,设置包含的脚本策略'unsafe-inline'将不起作用.