2017-02-25 55 views
5

我正在使用JQuery版本3.1.1,并试图在我的网页上实施内容安全策略指令。JQuery 3.1.1违反CSP指令

,我发现了以下错误:

Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' 'nonce-c20t41c7-73c6-4bf9-fde8-24a7b35t5f71'". Either the 'unsafe-inline' keyword, a hash ('sha256-KAcpKskREkEQf5B3mhDTonpPg34XnzaUC5IoBrOUrwY='), or a nonce ('nonce-...') is required to enable inline execution.

的错误是在主要的jquery.js脚本文件的82线生产。此行内容如下:

doc.head.appendChild(script).parentNode.removeChild(script); 

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

我不想使用'unsafe-inline'。有没有其他的方法来规避这个错误?如您在CSP违规中看到的,我使用CSP级别2(随机数),但它被忽略。在附加脚本标签时,是否有可能(如何)通知JQuery使用此随机数?

非常感谢。

亲切的问候, 五


UPDATE:这是HTML的样子(使用随机数快速模板)

<script nonce="<%=nonce%>" type="text/javascript" src="jquery.js"></script> 

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


UPDATE:它与普通的JavaScript

<script nonce="<%=nonce%>" type="text/javascript"> 
     var userEmail = "<%=user.user.email%>"; 
</script> 

没有现时属性这个脚本标签会违反CSP指令工作。

+0

它与工作只是JavaScript或如果你把直接的脚本在你的HTML? – bormat

+0

在附加到头部之前,您是否在脚本标记上设置了与'CSP'nonce(减去“nonce-”前缀)相匹配的'nonce'属性?如果您已经这样做了,可能看到脚本元素的外观和CSP头可能会有所帮助。 – Brian

+0

@bormat是的,它可以使用普通的javascript。 –

回答

2

看起来它如何追加内嵌脚本结束丢弃所有的属性可以和我的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); 
+0

有一件事很奇怪,尽管元素没有添加'nonce'属性。在我的开发工具和附加子元素之前/之后,在Chome开发工具的元素窗格中没有属性,它神奇地在那里,可以通过s2.getAttribute('nonce')来访问。从外观上看,或许我错过了正在追加的文档片段,但是特定的脚本标签没有得到执行,只有附加在'DOMEval'中的创建的文件片段可以解释为什么它看起来在元素中都很好,但CSP并不好:) – Brian

+1

我不认为'.innerHTML'在'script'元素上按预期工作。 http://stackoverflow.com/a/13392818/367865 – Ouroborus

+0

你是对的@Ouroborus,谢谢我修改过,所以它使用'textContent' - .'innerHTML'可以意外地转移事情 - 我弄糊涂了!谢谢:) – Brian

1

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

<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) 
} 
+0

感谢您的帮助,但不幸的是,您的解决方法不能解决JQuery在执行DOMEval函数时剥去脚本属性的问题。 –

+0

我编辑了,实际上jquery只保留src和属性并删除所有其他 – bormat