我有一个带有以下指令的元标记:
<meta http-equiv="Content-Security-Policy" content="base-uri 'self'; script-src 'self' 'sha256-s5EeESrvuQPpk2bpz5I3zn/R8Au2DYB1Z+YUH9p0fUE=' 'sha256-PYYfGnkbZ44B9ZBpgv8NbP3MXT560LMfrDSas2BveJo=';">
然后我在页面下方有两个内联脚本,每个脚本应该匹配策略中生成的一个sha。
在Chrome和Firefox中,我没有投诉,我的脚本按预期运行。
在Safari版本11.0.3(13604.5.6)中,出现以下错误:
Refused to execute a script because its hash, its nonce, or 'unsafe-inline' does not appear in the script-src directive of the Content Security Policy
我很困惑为什么!
不幸的是,我无法用它内部的问题产生最小的可重复回购 - 较小的示例在Safari中为我工作,所以它让我相信它与我的应用程序中的特定内容有关,可能与第二个相关我在下面试过的东西。
非常感谢任何帮助!
是否支持哈希?
根据this Stack Overflow post和Safari release notes,支持哈希的CSP 2.0在Safari 10中实现
正确的字符集?
以前,我看到的问题是因为我在计算基于UTF-8字符集的哈希值,但是在没有charset元标记的情况下将JS输出到浏览器。我的JS中的特殊字符被破坏,并且在浏览器尝试计算时会导致shas的差异。
我不相信这会影响我,因为Chrome和Firefox看不出任何问题,但也许我在这里错了?
Safari的 unsafe-inline
,然后允许哈希在Chrome和Firefox中覆盖它?
根据CSP规范,unsafe-inline
为ignored if a hash or nonce is present。 Safari 11也遵守此规定,因此添加unsafe-inline
关键字无效
答案 0 :(得分:2)
原来这是一个字符集问题。
我设法获得了一个可重复性最小的问题(经过一些试验和错误,并且运气很好!)并且发现我的一个角色在Safari中呈现之前和之后都有不同的sha。
在Safari中呈现之前,角色如下:
在Safari渲染了角色后,它是以下(即使在代码的源代码中):
奇怪的是,Chrome和Firefox都没有这个问题,因此它必须是Safari渲染后对字符进行规范化,或者在浏览器之间计算sha256
哈希时的差异。
解决方案是关闭UglifyJS中的字符压缩,使字符保持为\uF900
,而不是压缩到上图中的单个字符。
我在webpack.config.js文件中使用以下选项实现了这一点:
new UglifyJsPlugin({
uglifyOptions: {
output: {
// necessary to stop the minification of escaped unicode sequences into their actual chars.
// some unicode breaks CSP checks in safari
ascii_only: true,
},
},
}),
我已向Apple报告,看看他们是否会考虑修复此问题。
答案 1 :(得分:0)
另一种解决方案是确保脚本中的字符串已标准化。可以使用String.normalize在JavaScript中实现。
规范化确保每个Unicode字符均以其规范(NFC)形式表示,这似乎使Safari中的CSP哈希比较得以实现。因此,如果您要处理任何可能使用重音符号,非拉丁文字等的文本,则对字符串进行标准化是个好主意。