看起来它如何追加内嵌脚本结束丢弃所有的属性可以和我的jQuery的的错误或怪癖“T看到固定它 ,以测试它的一种明显的方式我用下面的HTML:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src http://localhost 'nonce-123456' ; child-src 'none'; object-src 'none'; script-src 'nonce-123456';">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.js" nonce="123456"></script> <!-- HTML nonce works -->
<script nonce="123456">
//This works
console.log('Inline nonce works');
//This will also work
var s = document.createElement('script');
s.setAttribute('nonce', '123456');
s.textContent = 'console.log("Dynamically generated inline tag works")';
document.head.appendChild(s);
// This won't work
var s2 = document.createElement('script');
s2.setAttribute('nonce', '123456');
s2.textContent = 'console.log("Dynamically generated inline tag appended via jQuery doesn\'t work")';
$(document.head).append(s2); // This will throw a CSP error
</script>
</head>
<body>
</body>
</html>
当使用jQuery追加它经过以下过程(降低略):
- 创建文档片段并追加脚本标记到它
- 应用一个
type="false/"
属性到脚本标签
- 移除
type
属性
- 如果
src
属性存在时,它通过AJAX检索脚本(未进一步调查)
- 如果不是,则运行
DOMEval(node.textContent.replace(rcleanScript, ""), doc)
DomEval
看起来像这样(添加了注释):
doc = doc || document;
var script = doc.createElement("script");
script.textContent = code;
doc.head.appendChild(script).parentNode.removeChild(script);
正如你可以看到它被附加和CSP等失败之前没有属性会结转到新的元素。
解决方法是只使用本地JS追加元素而不是jQuery,或者等待错误修复/对您报告的响应。我不确定他们的推理是如何以这种方式排除属性对于内联脚本标记可能是安全功能?
以下应该可以在没有jQuery的情况下实现您想要的功能 - 只需将textContent属性设置为您的JS源代码即可。
var script = document.createElement('script');
script.setAttribute('nonce', '<%=nonce%>');
script.textContent = '// Code here';
document.head.appendChild(script);
所以基本上,为什么那个特定的行抛出的错误是,在所附的标签实际上是用相同的代码创建一个新标签,并没有适用于它的属性和它没有nonce
它是由CSP拒绝。
更新:我已经修补jQuery来解决这个问题(是3.1.2-预修补,但通过所有测试),如果您使用我的上次修复,我建议更新到此版本!
精缩:http://pastebin.com/gcLexN7z
取消精缩:http://pastebin.com/AEvzir4H
分支可以在这里找到:https://github.com/Brian-Aykut/jquery/tree/3541-csp
问题链接:https://github.com/jquery/jquery/issues/3541
变化代码:
行〜 76将DOMEval
函数替换为:
function DOMEval(code, doc, attr) {
doc = doc || document;
attr = attr || {};
var script = doc.createElement("script");
for (var key in attr) {
if (attr.hasOwnProperty(key)) {
script.setAttribute(key, attr[ key ]);
}
}
script.text = code;
doc.head.appendChild(script).parentNode.removeChild(script);
}
对〜行5717 var
声明近线5790添加attr
到
var fragment, first, scripts, hasScripts, node, doc, attr,
变化else
身体:
attr = {};
if (node.hasAttribute && node.hasAttribute("nonce")) {
attr.nonce = node.getAttribute("nonce");
}
DOMEval(node.textContent.replace(rcleanScript, ""), doc, attr);
它与工作只是JavaScript或如果你把直接的脚本在你的HTML? – bormat
在附加到头部之前,您是否在脚本标记上设置了与'CSP'nonce(减去“nonce-”前缀)相匹配的'nonce'属性?如果您已经这样做了,可能看到脚本元素的外观和CSP头可能会有所帮助。 – Brian
@bormat是的,它可以使用普通的javascript。 –