41

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

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

清单.json:

{
    "name": "CSP Test",
    "version": "1.0",
    "manifest_version": 2,
    "options_page": "test.html",
    "content_security_policy": "default-src 'unsafe-inline'"
}

测试.html:

<html><head>
<script type="text/javascript">
        alert("hello");
</script>
</head></html>

在 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 文件中。

4

4 回答 4

37

对于 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'

例子

考虑以下:

清单.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"
  }
}

背景.html

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <script>alert('foo');</script>
  </body>
</html>

结果
内联脚本的警报对话框

进一步的调查

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

背景.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>

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

附录:生成哈希

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

  1. Python(将 JS 传递给标准输入,将其通过管道传递到其他地方):
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))
  1. 在 JS 中,使用Stanford Javascript Crypto Library
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);
}

确保在散列内联脚本时包含脚本标记的全部内容(包括所有前导/尾随空格)。如果您想将其合并到您的构建中,您可以使用类似Cheerio的工具来获取相关部分。通常,对于 any 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'`;

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

于 2016-07-24T16:58:56.443 回答
15

以下答案适用于旧版 Chrome (<46)。有关最新的,请查看@Chris-Hunt 答案https://stackoverflow.com/a/38554505/422670

我刚刚为这个问题发布了一个非常相似的答案https://stackoverflow.com/a/11670319/422670

如前所述,没有办法放松 v2 扩展中的内联安全策略unsafe-inline故意的,根本行不通。

除了将所有 javascript 移动到 js 文件中并用<script src>.

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

"sandbox": {
    "pages": [
      "page1.html",
      "directory/page2.html"
    ]
},

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

现在,Google 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'将不起作用。

于 2012-07-26T14:57:06.933 回答
3

内容安全策略级别 2 中允许内联脚本的哈希使用。从规范中的示例:

内容安全策略:script-src 'sha512-YWIzOWNiNzJjNDRlYzc4MTgwMDhmZDlkOWI0NTAyMjgyY2MyMWJlMWUyNjc1ODJlYWJhNjU5MGU4NmZmNGU3OAo='

另一种选择是nonce,同样来自示例:

内容安全策略:script-src 'self' 'nonce-$RANDOM';

然后

<script nonce="$RANDOM">...</script>
<script nonce="$RANDOM" src='save-because-nonce'></script>

这些似乎在 Chrome 40+ 中得到支持,但我不确定目前使用其他浏览器会有什么运气。

于 2015-06-22T04:01:03.673 回答
2

Afaik,这是一个错误。

"default-src 'self' https://ssl.google-analytics.com"

工作,而

"default-src 'self' http://ssl.google-analytics.com"

没有。

它确实是最前沿的技术,详情请查看http://code.google.com/p/chromium/issues/detail?id=105796

更新:http ://code.google.com/p/chromium/issues/detail?id=107538指的是这个问题。

于 2011-12-14T14:22:47.957 回答