2017-02-25 243 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