对于 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>
结果:
附录:生成哈希
以下是生成哈希的两种方法:
- 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))
- 在 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 插件。