看起來它如何追加內嵌腳本結束丟棄所有的屬性可以和我的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。 –