From c7c2855ed13f23322c4064407c1ed84561b95738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Mon, 14 Jan 2019 19:29:54 +0100 Subject: [PATCH] Core: Preserve CSP nonce on scripts in DOM manipulation Fixes gh-3541 Closes gh-4269 --- src/core/DOMEval.js | 10 ++++++++++ test/data/csp-nonce.html | 13 +++++++++++++ test/data/csp-nonce.js | 8 ++++++++ test/data/mock.php | 8 ++++++++ test/jquery.js | 2 +- test/middleware-mockserver.js | 8 ++++++++ test/unit/manipulation.js | 20 ++++++++++++++++++++ 7 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 test/data/csp-nonce.html create mode 100644 test/data/csp-nonce.js diff --git a/src/core/DOMEval.js b/src/core/DOMEval.js index 199ec9518..8d2d0023b 100644 --- a/src/core/DOMEval.js +++ b/src/core/DOMEval.js @@ -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 index 000000000..d35c33fc4 --- /dev/null +++ b/test/data/csp-nonce.html @@ -0,0 +1,13 @@ + + + + + CSP nonce Test Page + + + + + +

CSP nonce Test Page

+ + diff --git a/test/data/csp-nonce.js b/test/data/csp-nonce.js new file mode 100644 index 000000000..507e87e68 --- /dev/null +++ b/test/data/csp-nonce.js @@ -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 ); +} ); diff --git a/test/data/mock.php b/test/data/mock.php index 79110dc45..7e6aa1bec 100644 --- a/test/data/mock.php +++ b/test/data/mock.php @@ -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' ); } diff --git a/test/jquery.js b/test/jquery.js index 8ba139e6b..6b1aef42f 100644 --- a/test/jquery.js +++ b/test/jquery.js @@ -54,7 +54,7 @@ // Otherwise, load synchronously } else { - document.write( "