Title: [209759] trunk
Revision
209759
Author
[email protected]
Date
2016-12-13 10:21:37 -0800 (Tue, 13 Dec 2016)

Log Message

CSP: Teach the preload scanner about the 'nonce' attribute
https://bugs.webkit.org/show_bug.cgi?id=161192
<rdar://problem/28010354>

Reviewed by Darin Adler.

Source/WebCore:

This patch was inspired by a similar Blink change:
<https://chromium.googlesource.com/chromium/src/+/dde5487f380cf774e4c0e96ba7f88ea68e723907>

Preload external scripts and stylesheets whose HTML script and link elements have a nonce
attribute that is listed in the Content Security Policy (CSP) of the page.

Currently the preload scanner ignores the nonce attribute on HTML script and link elements.
So, WebKit does not preload their associated subresources unless the value of the src
attribute or href attribute is whitelisted in the CSP of the page for script and link
elements, respectively. Instead the preload scanner should recognize the nonce attribute on
script and link elements and query the CSP of the page with it. If the nonce attribute is
whitelisted then the request should be preloaded.

Tests: http/tests/loading/do-not-preload-css-blocked-by-csp.html
       http/tests/loading/do-not-preload-script-src-blocked-by-csp.html
       http/tests/loading/preload-css-with-csp-nonce.html
       http/tests/loading/preload-script-src-with-csp-nonce.html

* html/parser/HTMLPreloadScanner.cpp:
(WebCore::TokenPreloadScanner::StartTagScanner::createPreloadRequest): Set the nonce on the
PreloadRequest to the nonce that we found during the scan.
(WebCore::TokenPreloadScanner::StartTagScanner::processAttribute): For script and link tag names,
save the value of the nonce attribute (if it has one).
* html/parser/HTMLResourcePreloader.cpp:
(WebCore::PreloadRequest::resourceRequest): Skip CSP policy check if the nonce is listed in
the CSP of the page.
* html/parser/HTMLResourcePreloader.h:
(WebCore::PreloadRequest::setNonce): Added.

LayoutTests:

Add tests to ensure that we preload <script>s and <link>s whose nonce is allowed by the
Content Security Policy of the page.

* http/tests/loading/do-not-preload-css-blocked-by-csp-expected.txt: Added.
* http/tests/loading/do-not-preload-css-blocked-by-csp.html: Added.
* http/tests/loading/do-not-preload-script-src-blocked-by-csp-expected.txt: Added.
* http/tests/loading/do-not-preload-script-src-blocked-by-csp.html: Added.
* http/tests/loading/preload-css-with-csp-nonce-expected.txt: Added.
* http/tests/loading/preload-css-with-csp-nonce.html: Added.
* http/tests/loading/preload-script-src-with-csp-nonce-expected.txt: Added.
* http/tests/loading/preload-script-src-with-csp-nonce.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (209758 => 209759)


--- trunk/LayoutTests/ChangeLog	2016-12-13 17:39:27 UTC (rev 209758)
+++ trunk/LayoutTests/ChangeLog	2016-12-13 18:21:37 UTC (rev 209759)
@@ -1,3 +1,23 @@
+2016-12-13  Daniel Bates  <[email protected]>
+
+        CSP: Teach the preload scanner about the 'nonce' attribute
+        https://bugs.webkit.org/show_bug.cgi?id=161192
+        <rdar://problem/28010354>
+
+        Reviewed by Darin Adler.
+
+        Add tests to ensure that we preload <script>s and <link>s whose nonce is allowed by the
+        Content Security Policy of the page.
+
+        * http/tests/loading/do-not-preload-css-blocked-by-csp-expected.txt: Added.
+        * http/tests/loading/do-not-preload-css-blocked-by-csp.html: Added.
+        * http/tests/loading/do-not-preload-script-src-blocked-by-csp-expected.txt: Added.
+        * http/tests/loading/do-not-preload-script-src-blocked-by-csp.html: Added.
+        * http/tests/loading/preload-css-with-csp-nonce-expected.txt: Added.
+        * http/tests/loading/preload-css-with-csp-nonce.html: Added.
+        * http/tests/loading/preload-script-src-with-csp-nonce-expected.txt: Added.
+        * http/tests/loading/preload-script-src-with-csp-nonce.html: Added.
+
 2016-12-13  Antti Koivisto  <[email protected]>
 
         REGRESSION (r198990): Safari - Cannot edit content inside <details> in wysiwyg editor

Added: trunk/LayoutTests/http/tests/loading/do-not-preload-css-blocked-by-csp-expected.txt (0 => 209759)


--- trunk/LayoutTests/http/tests/loading/do-not-preload-css-blocked-by-csp-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/loading/do-not-preload-css-blocked-by-csp-expected.txt	2016-12-13 18:21:37 UTC (rev 209759)
@@ -0,0 +1,9 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+CONSOLE MESSAGE: Refused to load http://127.0.0.1:8000/loading/resources/small_mq.css because it does not appear in the style-src directive of the Content Security Policy.
+CONSOLE MESSAGE: Refused to load http://127.0.0.1:8000/loading/resources/small_mq.css because it does not appear in the style-src directive of the Content Security Policy.
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+This test makes sure that the Preload scanner does not preload a stylesheet resource that is blocked by the Content Security Policy of the page. 
+PASS

Added: trunk/LayoutTests/http/tests/loading/do-not-preload-css-blocked-by-csp.html (0 => 209759)


--- trunk/LayoutTests/http/tests/loading/do-not-preload-css-blocked-by-csp.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/loading/do-not-preload-css-blocked-by-csp.html	2016-12-13 18:21:37 UTC (rev 209759)
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+</script>
+<meta http-equiv="Content-Security-Policy" content="script-src http://127.0.0.1:8000/resources/slow-script.pl http://127.0.0.1:8000/resources/checkPreload.js 'nonce-check-for-preload'; style-src 'none'">
+<script src=""
+<script src=""
+<link rel="stylesheet" href="" nonce="dummy">
+</head>
+<body>
+This test makes sure that the Preload scanner does not preload a stylesheet resource that is blocked by the Content Security Policy of the page.
+<br>
+<script nonce="check-for-preload">
+checkForPreload("resources/small_mq.css", false);
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/loading/do-not-preload-script-src-blocked-by-csp-expected.txt (0 => 209759)


--- trunk/LayoutTests/http/tests/loading/do-not-preload-script-src-blocked-by-csp-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/loading/do-not-preload-script-src-blocked-by-csp-expected.txt	2016-12-13 18:21:37 UTC (rev 209759)
@@ -0,0 +1,9 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+CONSOLE MESSAGE: Refused to load http://127.0.0.1:8000/loading/resources/zero-length.js because it does not appear in the script-src directive of the Content Security Policy.
+CONSOLE MESSAGE: Refused to load http://127.0.0.1:8000/loading/resources/zero-length.js because it does not appear in the script-src directive of the Content Security Policy.
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+This test makes sure that the Preload scanner does not preload a script resource that is blocked by the Content Security Policy of the page. 
+PASS

Added: trunk/LayoutTests/http/tests/loading/do-not-preload-script-src-blocked-by-csp.html (0 => 209759)


--- trunk/LayoutTests/http/tests/loading/do-not-preload-script-src-blocked-by-csp.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/loading/do-not-preload-script-src-blocked-by-csp.html	2016-12-13 18:21:37 UTC (rev 209759)
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+</script>
+<meta http-equiv="Content-Security-Policy" content="script-src http://127.0.0.1:8000/resources/slow-script.pl http://127.0.0.1:8000/resources/checkPreload.js 'nonce-check-for-preload'">
+<script src=""
+<script src=""
+</head>
+<body>
+This test makes sure that the Preload scanner does not preload a script resource that is blocked by the Content Security Policy of the page.
+<br>
+<script nonce="check-for-preload">
+checkForPreload("resources/zero-length.js", false);
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/loading/preload-css-with-csp-nonce-expected.txt (0 => 209759)


--- trunk/LayoutTests/http/tests/loading/preload-css-with-csp-nonce-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/loading/preload-css-with-csp-nonce-expected.txt	2016-12-13 18:21:37 UTC (rev 209759)
@@ -0,0 +1,7 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+This test makes sure that the Preload scanner preloads a stylesheet resource with a nonce attribute. 
+PASS

Added: trunk/LayoutTests/http/tests/loading/preload-css-with-csp-nonce.html (0 => 209759)


--- trunk/LayoutTests/http/tests/loading/preload-css-with-csp-nonce.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/loading/preload-css-with-csp-nonce.html	2016-12-13 18:21:37 UTC (rev 209759)
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+</script>
+<meta http-equiv="Content-Security-Policy" content="script-src http://127.0.0.1:8000/resources/slow-script.pl http://127.0.0.1:8000/resources/checkPreload.js 'nonce-check-for-preload'; style-src 'nonce-dummy'">
+<script src=""
+<script src=""
+<link rel="stylesheet" href="" nonce="dummy">
+</head>
+<body>
+This test makes sure that the Preload scanner preloads a stylesheet resource with a nonce attribute.
+<br>
+<script nonce="check-for-preload">
+checkForPreload("resources/small_mq.css", true);
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/loading/preload-script-src-with-csp-nonce-expected.txt (0 => 209759)


--- trunk/LayoutTests/http/tests/loading/preload-script-src-with-csp-nonce-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/loading/preload-script-src-with-csp-nonce-expected.txt	2016-12-13 18:21:37 UTC (rev 209759)
@@ -0,0 +1,7 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+This test makes sure that the Preload scanner preloads a script resource with a nonce attribute. 
+PASS

Added: trunk/LayoutTests/http/tests/loading/preload-script-src-with-csp-nonce.html (0 => 209759)


--- trunk/LayoutTests/http/tests/loading/preload-script-src-with-csp-nonce.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/loading/preload-script-src-with-csp-nonce.html	2016-12-13 18:21:37 UTC (rev 209759)
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+</script>
+<meta http-equiv="Content-Security-Policy" content="script-src http://127.0.0.1:8000/resources/slow-script.pl http://127.0.0.1:8000/resources/checkPreload.js 'nonce-check-for-preload' 'nonce-dummy'">
+<script src=""
+<script src=""
+</head>
+<body>
+This test makes sure that the Preload scanner preloads a script resource with a nonce attribute.
+<br>
+<script nonce="check-for-preload">
+checkForPreload("resources/zero-length.js", true);
+</script>
+<script src="" nonce="dummy"></script>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (209758 => 209759)


--- trunk/Source/WebCore/ChangeLog	2016-12-13 17:39:27 UTC (rev 209758)
+++ trunk/Source/WebCore/ChangeLog	2016-12-13 18:21:37 UTC (rev 209759)
@@ -1,3 +1,40 @@
+2016-12-13  Daniel Bates  <[email protected]>
+
+        CSP: Teach the preload scanner about the 'nonce' attribute
+        https://bugs.webkit.org/show_bug.cgi?id=161192
+        <rdar://problem/28010354>
+
+        Reviewed by Darin Adler.
+
+        This patch was inspired by a similar Blink change:
+        <https://chromium.googlesource.com/chromium/src/+/dde5487f380cf774e4c0e96ba7f88ea68e723907>
+
+        Preload external scripts and stylesheets whose HTML script and link elements have a nonce
+        attribute that is listed in the Content Security Policy (CSP) of the page.
+
+        Currently the preload scanner ignores the nonce attribute on HTML script and link elements.
+        So, WebKit does not preload their associated subresources unless the value of the src
+        attribute or href attribute is whitelisted in the CSP of the page for script and link
+        elements, respectively. Instead the preload scanner should recognize the nonce attribute on
+        script and link elements and query the CSP of the page with it. If the nonce attribute is
+        whitelisted then the request should be preloaded.
+
+        Tests: http/tests/loading/do-not-preload-css-blocked-by-csp.html
+               http/tests/loading/do-not-preload-script-src-blocked-by-csp.html
+               http/tests/loading/preload-css-with-csp-nonce.html
+               http/tests/loading/preload-script-src-with-csp-nonce.html
+
+        * html/parser/HTMLPreloadScanner.cpp:
+        (WebCore::TokenPreloadScanner::StartTagScanner::createPreloadRequest): Set the nonce on the
+        PreloadRequest to the nonce that we found during the scan.
+        (WebCore::TokenPreloadScanner::StartTagScanner::processAttribute): For script and link tag names,
+        save the value of the nonce attribute (if it has one).
+        * html/parser/HTMLResourcePreloader.cpp:
+        (WebCore::PreloadRequest::resourceRequest): Skip CSP policy check if the nonce is listed in
+        the CSP of the page.
+        * html/parser/HTMLResourcePreloader.h:
+        (WebCore::PreloadRequest::setNonce): Added.
+
 2016-12-13  Dave Hyatt  <[email protected]>
 
         [CSS Parser] Rename CSSPrimitiveValue::UnitTypes to CSSPrimitiveValue::UnitType

Modified: trunk/Source/WebCore/html/parser/HTMLPreloadScanner.cpp (209758 => 209759)


--- trunk/Source/WebCore/html/parser/HTMLPreloadScanner.cpp	2016-12-13 17:39:27 UTC (rev 209758)
+++ trunk/Source/WebCore/html/parser/HTMLPreloadScanner.cpp	2016-12-13 18:21:37 UTC (rev 209759)
@@ -147,6 +147,7 @@
 
         auto request = std::make_unique<PreloadRequest>(initiatorFor(m_tagId), m_urlToLoad, predictedBaseURL, resourceType(), m_mediaAttribute, m_moduleScript);
         request->setCrossOriginMode(m_crossOriginMode);
+        request->setNonce(m_nonceAttribute);
 
         // According to the spec, the module tag ignores the "charset" attribute as the same to the worker's
         // importScript. But WebKit supports the "charset" for importScript intentionally. So to be consistent,
@@ -216,7 +217,8 @@
                     m_moduleScript = equalLettersIgnoringASCIICase(attributeValue, "module") ? PreloadRequest::ModuleScript::Yes : PreloadRequest::ModuleScript::No;
                     break;
                 }
-            }
+            } else if (match(attributeName, nonceAttr))
+                m_nonceAttribute = attributeValue;
             processImageAndScriptAttribute(attributeName, attributeValue);
             break;
         case TagId::Link:
@@ -230,6 +232,8 @@
                 m_charset = attributeValue;
             else if (match(attributeName, crossoriginAttr))
                 m_crossOriginMode = stripLeadingAndTrailingHTMLSpaces(attributeValue);
+            else if (match(attributeName, nonceAttr))
+                m_nonceAttribute = attributeValue;
             break;
         case TagId::Input:
             if (match(attributeName, srcAttr))
@@ -326,6 +330,7 @@
     String m_crossOriginMode;
     bool m_linkIsStyleSheet;
     String m_mediaAttribute;
+    String m_nonceAttribute;
     String m_metaContent;
     bool m_metaIsViewport;
     bool m_inputIsImage;

Modified: trunk/Source/WebCore/html/parser/HTMLResourcePreloader.cpp (209758 => 209759)


--- trunk/Source/WebCore/html/parser/HTMLResourcePreloader.cpp	2016-12-13 17:39:27 UTC (rev 209758)
+++ trunk/Source/WebCore/html/parser/HTMLResourcePreloader.cpp	2016-12-13 18:21:37 UTC (rev 209759)
@@ -43,7 +43,18 @@
 CachedResourceRequest PreloadRequest::resourceRequest(Document& document)
 {
     ASSERT(isMainThread());
-    CachedResourceRequest request(completeURL(document), CachedResourceLoader::defaultCachedResourceOptions());
+
+    bool skipContentSecurityPolicyCheck = false;
+    if (m_resourceType == CachedResource::Type::Script)
+        skipContentSecurityPolicyCheck = document.contentSecurityPolicy()->allowScriptWithNonce(m_nonceAttribute);
+    else if (m_resourceType == CachedResource::Type::CSSStyleSheet)
+        skipContentSecurityPolicyCheck = document.contentSecurityPolicy()->allowStyleWithNonce(m_nonceAttribute);
+
+    ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions();
+    if (skipContentSecurityPolicyCheck)
+        options.contentSecurityPolicyImposition = ContentSecurityPolicyImposition::SkipPolicyCheck;
+
+    CachedResourceRequest request { completeURL(document), options };
     request.setInitiator(m_initiator);
     String crossOriginMode = m_crossOriginMode;
     if (m_moduleScript == ModuleScript::Yes) {

Modified: trunk/Source/WebCore/html/parser/HTMLResourcePreloader.h (209758 => 209759)


--- trunk/Source/WebCore/html/parser/HTMLResourcePreloader.h	2016-12-13 17:39:27 UTC (rev 209758)
+++ trunk/Source/WebCore/html/parser/HTMLResourcePreloader.h	2016-12-13 18:21:37 UTC (rev 209759)
@@ -53,6 +53,7 @@
     const String& media() const { return m_mediaAttribute; }
     void setCharset(const String& charset) { m_charset = charset.isolatedCopy(); }
     void setCrossOriginMode(const String& mode) { m_crossOriginMode = mode; }
+    void setNonce(const String& nonce) { m_nonceAttribute = nonce; }
     CachedResource::Type resourceType() const { return m_resourceType; }
 
 private:
@@ -65,6 +66,7 @@
     CachedResource::Type m_resourceType;
     String m_mediaAttribute;
     String m_crossOriginMode;
+    String m_nonceAttribute;
     ModuleScript m_moduleScript;
 };
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to