JQueryバージョン3.1.1を使用していて、Webページにコンテンツセキュリティポリシーディレクティブを実装しようとしています。
次のエラーが発生します:
次のコンテンツセキュリティポリシーディレクティブに違反しているため、インラインスクリプトの実行を拒否しました: "script-src'self''nonce-c20t41c7-73c6-4bf9-fde8-24a7b35t5f71 '"。インライン実行を有効にするには、「unsafe-inline」キーワード、ハッシュ( 'sha256-KAcpKskREkEQf5B3mhDTonpPg34XnzaUC5IoBrOUrwY =')、またはナンス( 'nonce -...')のいずれかが必要です。
エラーは、メインのjquery.jsスクリプトファイルの82行目に表示されます。この行の内容は次のとおりです。
doc.head.appendChild( script ).parentNode.removeChild( script );
基本的に、これはCSPに違反するインラインスクリプトタグをDOMに追加します。
'unsafe-inline'
は使いたくない。このエラーを回避する他の方法はありますか?
CSP違反でわかるように、私はCSPレベル2(nonce)を使用していますが、無視されます。スクリプトタグを追加するときにこのナンスを使用するようにjQueryに通知することは(何らかの方法で)可能でしょうか?
PDATE:これはHTMLがどのように見えるかです(nonceにExpressテンプレートを使用)
<script nonce="<%=nonce%>" type="text/javascript" src="jquery.js"></script>
HTMLがレンダリングされると、scriptタグのnonce属性は、サーバーから送信されたCSPnonceディレクティブと一致します。
PDATE:プレーンJavaScriptで動作します
<script nonce="<%=nonce%>" type="text/javascript">
var userEmail = "<%=user.user.email%>";
</script>
Nonce属性がないと、このスクリプトタグはCSPディレクティブに違反します。
インラインスクリプトを追加するjQueryのバグまたは癖のように見えますが、最終的にすべての属性が破棄され、次の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は失敗します。
解決策は、jQueryではなくネイティブJSを使用して要素を追加するか、レポートへのバグ修正/応答を待つことです。インラインスクリプトタグの属性をこの方法で除外する理由がわからないのですが、セキュリティ機能かもしれません。
以下は、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のattr
ステートメントに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 );
_
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)
}