首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >jQuery 3.1.1违反CSP指令

jQuery 3.1.1违反CSP指令
EN

Stack Overflow用户
提问于 2017-02-25 00:46:31
回答 2查看 15.8K关注 0票数 14

我正在使用jQuery 3.1.1版本,并试图在我的网页上实现内容安全策略 (CSP)指令。

我得到了以下错误:

拒绝执行内联脚本,因为它违反了以下内容安全策略指令:" script -src 'self‘'nonce-c20t41c7-73c6-4bf9-fde8-24a7b35t5f71'".要么是‘不安全-内联’关键字,要么是散列('sha256-KAcpKskREkEQf5B3mhDTonpPg34XnzaUC5IoBrOUrwY='),,要么是“不安全-.”)需要启用内联执行。

错误发生在主jquery.js脚本文件的第82行。这一行的内容是:

代码语言:javascript
复制
doc.head.appendChild( script ).parentNode.removeChild( script );

基本上,它向DOM添加了一个内联脚本标记,这违反了CSP。

我不想使用'unsafe-inline'。还有其他方法可以避免这个错误吗?

正如您在CSP违规事件上所看到的那样,我使用的是CSP级别2(现在),但是它被忽略了。在追加脚本标记时,是否可以(以某种方式)通知jQuery使用这个nonce?

这就是HTML的样子(使用Express.js模板作为当前的模板)

代码语言:javascript
复制
<script nonce="<%=nonce%>" type="text/javascript" src="jquery.js"></script>

一旦呈现HTML,脚本标记上的nonce属性就与服务器发送的CSP指令相匹配。

它确实适用于普通的JavaScript:

代码语言:javascript
复制
<script nonce="<%=nonce%>" type="text/javascript">
        var userEmail = "<%=user.user.email%>";
</script>

如果没有nonce属性,这个脚本标记将违反CSP指令。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-02-26 02:30:50

它看起来像是jQuery的一个bug或怪癖,它是如何附加内联脚本的,最终丢弃了它们的所有属性,我看不出有一种明显的方法来修复它来测试它--我使用了以下HTML:

代码语言:javascript
复制
<!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看起来如下(添加了注释):

代码语言:javascript
复制
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源代码即可。

代码语言: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函数替换为:

代码语言:javascript
复制
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语句中

代码语言:javascript
复制
var fragment, first, scripts, hasScripts, node, doc, attr,

将第5790行附近的else体更改为:

代码语言:javascript
复制
attr = {};
if ( node.hasAttribute && node.hasAttribute( "nonce" ) ) {
    attr.nonce = node.getAttribute( "nonce" );
}
DOMEval( node.textContent.replace( rcleanScript, "" ), doc, attr );
票数 2
EN

Stack Overflow用户

发布于 2017-02-25 20:27:47

好的,您只想包含jQuery,所以您需要在jQuery脚本之前和删除自定义函数之后重新定义函数appendChild (以禁用它)。

代码语言:javascript
复制
<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的附加函数:

代码语言:javascript
复制
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)
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42450608

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档