]> source.dussan.org Git - jquery.git/commitdiff
Core: Support passing nonce through jQuery.globalEval
authorMichał Gołębiowski-Owczarek <m.goleb@gmail.com>
Mon, 21 Jan 2019 17:42:39 +0000 (18:42 +0100)
committerGitHub <noreply@github.com>
Mon, 21 Jan 2019 17:42:39 +0000 (18:42 +0100)
Fixes gh-4278
Closes gh-4280
Ref gh-3541
Ref gh-4269

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

index 84f9afe13bbed6beef12dd47981dc88a7e620fde..d9c7e988262461ad5faa46855e046e31ea98d631 100644 (file)
@@ -238,8 +238,8 @@ jQuery.extend( {
        },
 
        // Evaluates a script in a global context
-       globalEval: function( code ) {
-               DOMEval( code );
+       globalEval: function( code, options ) {
+               DOMEval( code, { nonce: options && options.nonce } );
        },
 
        each: function( obj, callback ) {
index 8d2d0023b354cea0bf65ddd4862bb46c3434da0e..59f6e024775f697f3863235666bb73dac6339a42 100644 (file)
@@ -10,26 +10,29 @@ define( [
                noModule: true
        };
 
-       function DOMEval( code, doc, node ) {
+       function DOMEval( code, node, doc ) {
                doc = doc || document;
 
-               var i,
+               var i, val,
                        script = doc.createElement( "script" );
 
                script.text = code;
                if ( node ) {
                        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 ) );
+                               // Support: Firefox 64+, Edge 18+
+                               // Some browsers don't support the "nonce" property on scripts.
+                               // On the other hand, just using `getAttribute` is not enough as
+                               // the `nonce` attribute is reset to an empty string whenever it
+                               // becomes browsing-context connected.
+                               // See https://github.com/whatwg/html/issues/2369
+                               // See https://html.spec.whatwg.org/#nonce-attributes
+                               // The `node.getAttribute` check was added for the sake of
+                               // `jQuery.globalEval` so that it can fake a nonce-containing node
+                               // via an object.
+                               val = node[ i ] || node.getAttribute && node.getAttribute( i );
+                               if ( val ) {
+                                       script.setAttribute( i, val );
                                }
                        }
                }
index 042728573464861c54c4d56eda3fd9f2f25212be..a24a5cc0c15c402651261278d2fad650735319a4 100644 (file)
@@ -202,7 +202,7 @@ function domManip( collection, args, callback, ignored ) {
                                                                jQuery._evalUrl( node.src );
                                                        }
                                                } else {
-                                                       DOMEval( node.textContent.replace( rcleanScript, "" ), doc, node );
+                                                       DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
                                                }
                                        }
                                }
diff --git a/test/data/csp-nonce-globaleval.html b/test/data/csp-nonce-globaleval.html
new file mode 100644 (file)
index 0000000..aa620c5
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+       <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+       <title>CSP nonce via jQuery.globalEval 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-globaleval.js"></script>
+</head>
+<body>
+       <p>CSP nonce via jQuery.globalEval Test Page</p>
+</body>
+</html>
diff --git a/test/data/csp-nonce-globaleval.js b/test/data/csp-nonce-globaleval.js
new file mode 100644 (file)
index 0000000..23d549f
--- /dev/null
@@ -0,0 +1,5 @@
+/* global startIframeTest */
+
+jQuery( function() {
+       $.globalEval( "startIframeTest()", { nonce: "jquery+hardcoded+nonce" } );
+} );
index 7e6aa1becfa5598120ac335cabf6903d1020deb0..52de8ae9dc22542de4cc11ddabf27754d7b92357 100644 (file)
@@ -201,9 +201,10 @@ ok( true, "mock executed");';
        protected function cspNonce( $req ) {
                // This is CSP only for browsers with "Content-Security-Policy" header support
                // i.e. no old WebKit or old Firefox
+               $test = $req->query['test'] ? '-' . $req->query['test'] : '';
                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' );
+               echo file_get_contents( __DIR__ . '/csp-nonce' . $test . '.html' );
        }
 
        protected function cspLog( $req ) {
index feed281488dc98d2fcda9ac1b44098b2bdef6dbe..12c2e7533231ed4bb9aa054f0632d70ea21fb317 100644 (file)
@@ -208,11 +208,13 @@ var mocks = {
                resp.end( body );
        },
        cspNonce: function( req, resp ) {
+               var testParam = req.query.test ? "-" + req.query.test : "";
                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();
+               var body = fs.readFileSync(
+                       __dirname + "/data/csp-nonce" + testParam + ".html" ).toString();
                resp.end( body );
        },
        cspLog: function( req, resp ) {
index 7f30ddf25daf6d3a50330496c44376d0e8977f88..0acb45f3ed16a84bb016c3ec50a00855d75392fb 100644 (file)
@@ -2888,3 +2888,26 @@ testIframe(
        // script-src restrictions completely.
        QUnit[ /\bedge\/|iphone os [789]|android 4\./i.test( navigator.userAgent ) ? "skip" : "test" ]
 );
+
+testIframe(
+       "jQuery.globalEval supports nonce",
+       "mock.php?action=cspNonce&test=globaleval",
+       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+, iOS 7-9 only, Android 4.0-4.4 only
+       // Edge doesn't support nonce in non-inline scripts.
+       // See https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/13246371/
+       // Old iOS & Android Browser versions support script-src but not nonce, making this test
+       // impossible to run. Browsers not supporting CSP at all are not a problem as they'll skip
+       // script-src restrictions completely.
+       QUnit[ /\bedge\/|iphone os [789]|android 4\./i.test( navigator.userAgent ) ? "skip" : "test" ]
+);