web-dev-qa-db-ja.com

JQuery 3.1.1CSPディレクティブの違反

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ディレクティブに違反します。

10
Victor Gaspar

インラインスクリプトを追加する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 );  
_
2
Brian

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)
}
1
bormat