]> source.dussan.org Git - jquery.git/commitdiff
Core: Preserve CSP nonce on scripts in DOM manipulation
authorMichał Gołębiowski-Owczarek <m.goleb@gmail.com>
Mon, 14 Jan 2019 18:29:54 +0000 (19:29 +0100)
committerGitHub <noreply@github.com>
Mon, 14 Jan 2019 18:29:54 +0000 (19:29 +0100)
Fixes gh-3541
Closes gh-4269

src/core/DOMEval.js
test/data/csp-nonce.html [new file with mode: 0644]
test/data/csp-nonce.js [new file with mode: 0644]
test/data/mock.php
test/jquery.js
test/middleware-mockserver.js
test/unit/manipulation.js

index 199ec9518ff36de1ffdebe372836ee6470b3a70e..8d2d0023b354cea0bf65ddd4862bb46c3434da0e 100644 (file)
@@ -6,6 +6,7 @@ define( [
        var preservedScriptAttributes = {
                type: true,
                src: true,
+               nonce: true,
                noModule: true
        };
 
@@ -20,6 +21,15 @@ define( [
                        for ( i in preservedScriptAttributes ) {
                                if ( node[ i ] ) {
                                        script[ i ] = node[ i ];
+                               } else if ( node.getAttribute( i ) ) {
+
+                                       // Support: Firefox 64+, Edge 18+
+                                       // Some browsers don't support the "nonce" property on scripts.
+                                       // On the other hand, just using `setAttribute` & `getAttribute`
+                                       // is not enough as `nonce` is no longer exposed as an attribute
+                                       // in the latest standard.
+                                       // See https://github.com/whatwg/html/issues/2369
+                                       script.setAttribute( i, node.getAttribute( i ) );
                                }
                        }
                }
diff --git a/test/data/csp-nonce.html b/test/data/csp-nonce.html
new file mode 100644 (file)
index 0000000..d35c33f
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+       <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+       <title>CSP nonce Test Page</title>
+       <script nonce="jquery+hardcoded+nonce" src="../jquery.js"></script>
+       <script nonce="jquery+hardcoded+nonce" src="iframeTest.js"></script>
+       <script nonce="jquery+hardcoded+nonce" src="csp-nonce.js"></script>
+</head>
+<body>
+       <p>CSP nonce Test Page</p>
+</body>
+</html>
diff --git a/test/data/csp-nonce.js b/test/data/csp-nonce.js
new file mode 100644 (file)
index 0000000..507e87e
--- /dev/null
@@ -0,0 +1,8 @@
+/* global startIframeTest */
+
+jQuery( function() {
+       var script = document.createElement( "script" );
+       script.setAttribute( "nonce", "jquery+hardcoded+nonce" );
+       script.innerHTML = "startIframeTest()";
+       $( document.head ).append( script );
+} );
index 79110dc45453894345923eeb779f688880ce6903..7e6aa1becfa5598120ac335cabf6903d1020deb0 100644 (file)
@@ -198,6 +198,14 @@ ok( true, "mock executed");';
                echo file_get_contents( __DIR__ . '/csp.include.html' );
        }
 
+       protected function cspNonce( $req ) {
+               // This is CSP only for browsers with "Content-Security-Policy" header support
+               // i.e. no old WebKit or old Firefox
+               header( "Content-Security-Policy: script-src 'nonce-jquery+hardcoded+nonce'; report-uri ./mock.php?action=cspLog" );
+               header( 'Content-type: text/html' );
+               echo file_get_contents( __DIR__ . '/csp-nonce.html' );
+       }
+
        protected function cspLog( $req ) {
                file_put_contents( $this->cspFile, 'error' );
        }
index 8ba139e6baecdb117b6bf194ec0a1c33e2391a58..6b1aef42f6c8bda2f0435900ce9613a1d149b515 100644 (file)
@@ -54,7 +54,7 @@
 
        // Otherwise, load synchronously
        } else {
-               document.write( "<script id='jquery-js' src='" + parentUrl + src + "'><\x2Fscript>" );
+               document.write( "<script id='jquery-js' nonce='jquery+hardcoded+nonce' src='" + parentUrl + src + "'><\x2Fscript>" );
        }
 
 } )();
index 09371bbe90dd694db9231d96895f8bfd5ff23037..feed281488dc98d2fcda9ac1b44098b2bdef6dbe 100644 (file)
@@ -207,6 +207,14 @@ var mocks = {
                var body = fs.readFileSync( __dirname + "/data/csp.include.html" ).toString();
                resp.end( body );
        },
+       cspNonce: function( req, resp ) {
+               resp.writeHead( 200, {
+                       "Content-Type": "text/html",
+                       "Content-Security-Policy": "script-src 'nonce-jquery+hardcoded+nonce'; report-uri /base/test/data/mock.php?action=cspLog"
+               } );
+               var body = fs.readFileSync( __dirname + "/data/csp-nonce.html" ).toString();
+               resp.end( body );
+       },
        cspLog: function( req, resp ) {
                cspLog = "error";
                resp.writeHead( 200 );
index 300add5ec7c6946e70db6b7f78f6550c212a8c26..c8d5cdefe670e77e92f92783b2c82c485de3fc48 100644 (file)
@@ -2835,3 +2835,23 @@ QUnit.test( "Ignore content from unsuccessful responses (gh-4126)", 1, function(
                jQuery.globalEval = globalEval;
        }
 } );
+
+testIframe(
+       "Check if CSP nonce is preserved",
+       "mock.php?action=cspNonce",
+       function( assert, jQuery, window, document ) {
+               var done = assert.async();
+
+               assert.expect( 1 );
+
+               supportjQuery.get( baseURL + "support/csp.log" ).done( function( data ) {
+                       assert.equal( data, "", "No log request should be sent" );
+                       supportjQuery.get( baseURL + "mock.php?action=cspClean" ).done( done );
+               } );
+       },
+
+       // Support: Edge 18+
+       // Edge doesn't support nonce in non-inline scripts.
+       // See https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/13246371/
+       QUnit[ /\bedge\//i.test( navigator.userAgent ) ? "skip" : "test" ]
+);