我正在使用jQuery 3.1.1版本,并试图在我的网页上实现内容安全策略 (CSP)指令。
我得到了以下错误:
拒绝执行内联脚本,因为它违反了以下内容安全策略指令:" script -src 'self‘'nonce-c20t41c7-73c6-4bf9-fde8-24a7b35t5f71'".要么是‘不安全-内联’关键字,要么是散列('sha256-KAcpKskREkEQf5B3mhDTonpPg34XnzaUC5IoBrOUrwY='),,要么是“不安全-.”)需要启用内联执行。
错误发生在主jquery.js脚本文件的第82行。这一行的内容是:
doc.head.appendChild( script ).parentNode.removeChild( script );基本上,它向DOM添加了一个内联脚本标记,这违反了CSP。
我不想使用'unsafe-inline'。还有其他方法可以避免这个错误吗?
正如您在CSP违规事件上所看到的那样,我使用的是CSP级别2(现在),但是它被忽略了。在追加脚本标记时,是否可以(以某种方式)通知jQuery使用这个nonce?
这就是HTML的样子(使用Express.js模板作为当前的模板)
<script nonce="<%=nonce%>" type="text/javascript" src="jquery.js"></script>一旦呈现HTML,脚本标记上的nonce属性就与服务器发送的CSP指令相匹配。
它确实适用于普通的JavaScript:
<script nonce="<%=nonce%>" type="text/javascript">
var userEmail = "<%=user.user.email%>";
</script>如果没有nonce属性,这个脚本标记将违反CSP指令。
发布于 2017-02-26 02:30:50
它看起来像是jQuery的一个bug或怪癖,它是如何附加内联脚本的,最终丢弃了它们的所有属性,我看不出有一种明显的方法来修复它来测试它--我使用了以下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失败。
解决方案是只使用本机JavaScript来追加元素,而不是jQuery,或者可能等待对报告的bug修复/响应。我不确定他们以这种方式排除内联脚本标记(也许是安全特性)属性的理由是什么?
在没有jQuery的情况下,以下内容应该可以实现您想要的结果--只需将textContent属性设置为您的JavaScript源代码即可。
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 );
}将attr添加到~第5717行的var语句中
var fragment, first, scripts, hasScripts, node, doc, attr,将第5790行附近的else体更改为:
attr = {};
if ( node.hasAttribute && node.hasAttribute( "nonce" ) ) {
attr.nonce = node.getAttribute( "nonce" );
}
DOMEval( node.textContent.replace( rcleanScript, "" ), doc, attr );发布于 2017-02-25 20:27:47
好的,您只想包含jQuery,所以您需要在jQuery脚本之前和删除自定义函数之后重新定义函数appendChild (以禁用它)。
<script>
var oldAppend = document.head.appendChild
document.head.appendChild = function(script){
if(script && script.tagName=='SCRIPT'){
document.createElement('fakeHead').appendChild(script)//because script need a parent in the line that create the error
return script
}
return oldAppend.apply(this,arguments)
}
</script>
<script nonce="<%=nonce%>" type="text/javascript" src="jquery.js"></script>
<script>
document.head.appendChild = oldAppend
</script>尝尝这个。它将重新定义jQuery的附加函数:
var oldAppend = $.fn.append
$.fn.append = function($el){
var dom = ($el instanceOf $) ? $el[0] : $el
if(dom && dom.tagName=='SCRIPT'){
this[0].appendChild(dom)
return this
}
return oldAppend.apply(this,arguments)
}https://stackoverflow.com/questions/42450608
复制相似问题