Title: [220549] trunk
Revision
220549
Author
cdu...@apple.com
Date
2017-08-10 14:51:15 -0700 (Thu, 10 Aug 2017)

Log Message

[Beacon] Do connect-src CSP check on redirects as well
https://bugs.webkit.org/show_bug.cgi?id=175410
<rdar://problem/33815470>

Reviewed by Youenn Fablet.

Source/WebCore:

Pass ContentSecurityPolicy object to createPingHandle so that we can send
enough data to the NetworkProcess so do CSP checks for Ping loads such
as Beacon. For the IPC, we serialize the ContentSecurityPolicy's response
headers. Those headers are now cached in ContentSecurityPolicy for
performance reasons. CSP headers are rarely updated in practice but
sendBeacon() may get called repeatedly for a given document.

Tests: http/wpt/beacon/connect-src-beacon-redirect-allowed.sub.html
       http/wpt/beacon/connect-src-beacon-redirect-blocked.sub.html

* loader/LoaderStrategy.h:
* loader/PingLoader.cpp:
(WebCore::PingLoader::loadImage):
(WebCore::PingLoader::sendPing):
(WebCore::PingLoader::sendViolationReport):
(WebCore::PingLoader::startPingLoad):
* loader/PingLoader.h:
* loader/cache/CachedResource.cpp:
(WebCore::CachedResource::load):
* page/csp/ContentSecurityPolicy.cpp:
(WebCore::ContentSecurityPolicy::responseHeaders const):
(WebCore::ContentSecurityPolicy::didReceiveHeader):
* page/csp/ContentSecurityPolicy.h:
* page/csp/ContentSecurityPolicyResponseHeaders.h:
(WebCore::ContentSecurityPolicyResponseHeaders::encode const):
(WebCore::ContentSecurityPolicyResponseHeaders::decode):

Source/WebKit:

Pass CSP Response headers to the NetworkProcess via NetworkResourceLoadParameters
when doing a PingLoad. This allows PingLoad to do CSP checks (in particular
connect-src ones) in case the ping load gets redirected. Those checks need to be
done on the NetworkProcess side at this point because there is no guarantee the
WebContent process is still around.

To do the CSP checks, PingLoad lazily reconstructs a ContentSecurityPolicy object
from the CSP response headers.

* NetworkProcess/NetworkResourceLoadParameters.cpp:
(WebKit::NetworkResourceLoadParameters::encode const):
(WebKit::NetworkResourceLoadParameters::decode):
* NetworkProcess/NetworkResourceLoadParameters.h:
* NetworkProcess/PingLoad.cpp:
(WebKit::PingLoad::willPerformHTTPRedirection):
(WebKit::PingLoad::contentSecurityPolicy):
* NetworkProcess/PingLoad.h:
* WebProcess/Network/WebLoaderStrategy.cpp:
(WebKit::WebLoaderStrategy::createPingHandle):
* WebProcess/Network/WebLoaderStrategy.h:

Source/WebKitLegacy:

Update createPingHandle() to take in ContentSecurityPolicy
object in but no behavior change for WK1.

* WebCoreSupport/WebResourceLoadScheduler.cpp:
(WebResourceLoadScheduler::createPingHandle):
* WebCoreSupport/WebResourceLoadScheduler.h:

LayoutTests:

Add layout test coverage.

* http/wpt/beacon/connect-src-beacon-redirect-allowed.sub-expected.txt: Added.
* http/wpt/beacon/connect-src-beacon-redirect-allowed.sub.html: Added.
* http/wpt/beacon/connect-src-beacon-redirect-blocked.sub-expected.txt: Added.
* http/wpt/beacon/connect-src-beacon-redirect-blocked.sub.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (220548 => 220549)


--- trunk/LayoutTests/ChangeLog	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/LayoutTests/ChangeLog	2017-08-10 21:51:15 UTC (rev 220549)
@@ -1,3 +1,18 @@
+2017-08-10  Chris Dumez  <cdu...@apple.com>
+
+        [Beacon] Do connect-src CSP check on redirects as well
+        https://bugs.webkit.org/show_bug.cgi?id=175410
+        <rdar://problem/33815470>
+
+        Reviewed by Youenn Fablet.
+
+        Add layout test coverage.
+
+        * http/wpt/beacon/connect-src-beacon-redirect-allowed.sub-expected.txt: Added.
+        * http/wpt/beacon/connect-src-beacon-redirect-allowed.sub.html: Added.
+        * http/wpt/beacon/connect-src-beacon-redirect-blocked.sub-expected.txt: Added.
+        * http/wpt/beacon/connect-src-beacon-redirect-blocked.sub.html: Added.
+
 2017-08-10  Jonathan Bedard  <jbed...@apple.com>
 
         Mark webgl/webgl-box-shadow.html and webgl/webgl-border.html as failing for ios-device.

Added: trunk/LayoutTests/http/wpt/beacon/connect-src-beacon-redirect-allowed.sub-expected.txt (0 => 220549)


--- trunk/LayoutTests/http/wpt/beacon/connect-src-beacon-redirect-allowed.sub-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/beacon/connect-src-beacon-redirect-allowed.sub-expected.txt	2017-08-10 21:51:15 UTC (rev 220549)
@@ -0,0 +1,3 @@
+
+PASS Redirect is allowed by CSP 
+

Added: trunk/LayoutTests/http/wpt/beacon/connect-src-beacon-redirect-allowed.sub.html (0 => 220549)


--- trunk/LayoutTests/http/wpt/beacon/connect-src-beacon-redirect-allowed.sub.html	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/beacon/connect-src-beacon-redirect-allowed.sub.html	2017-08-10 21:51:15 UTC (rev 220549)
@@ -0,0 +1,53 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>SendBeacon CSP checking on redirect</title>
+    <script src=""
+    <script src=""
+  </head>
+  <body>
+    <script src=""
+    <script src=""
+    <script>
+var RESOURCES_DIR = "/WebKit/beacon/resources/";
+    let metaElement = document.createElement("meta");
+    metaElement.httpEquiv = "Content-Security-Policy";
+    metaElement.content = "connect-src 'self' " + get_host_info().HTTP_REMOTE_ORIGIN;
+    document.head.appendChild(metaElement);
+
+function pollResult(test, id) {
+  var checkUrl = RESOURCES_DIR + "beacon-preflight.py?cmd=get&id=" + id;
+
+  return new Promise(resolve => {
+    step_timeout(test.step_func(() => {
+      fetch(checkUrl).then(response => {
+        response.json().then(body => {
+          resolve(body);
+        });
+      });
+    }), 1000);
+  });
+}
+
+function testCORSPreflightRedirectSuccess(what) {
+  var testBase = get_host_info().HTTP_REMOTE_ORIGIN + RESOURCES_DIR;
+  var id = self.token();
+  var target = encodeURIComponent(testBase + "beacon-preflight.py?allowCors=1&cmd=put&id=" + id);
+
+  // 307 & 308 redirections are the only ones that maintain the POST method.
+  var testUrl = RESOURCES_DIR + "redirect.py?redirect_status=307&location=" + target;
+
+  promise_test(function(test) {
+    assert_true(navigator.sendBeacon(testUrl, what), "SendBeacon Succeeded");
+    return pollResult(test, id) .then(result => {
+      assert_equals(result['preflight'], 0, "Did not receive preflight")
+      assert_equals(result['beacon'], 1, "Received beacon")
+    });
+  }, "Redirect is allowed by CSP");
+}
+
+testCORSPreflightRedirectSuccess("123");
+    </script>
+  </body>
+</html>

Added: trunk/LayoutTests/http/wpt/beacon/connect-src-beacon-redirect-blocked.sub-expected.txt (0 => 220549)


--- trunk/LayoutTests/http/wpt/beacon/connect-src-beacon-redirect-blocked.sub-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/beacon/connect-src-beacon-redirect-blocked.sub-expected.txt	2017-08-10 21:51:15 UTC (rev 220549)
@@ -0,0 +1,3 @@
+
+PASS Redirect is blocked by CSP 
+

Added: trunk/LayoutTests/http/wpt/beacon/connect-src-beacon-redirect-blocked.sub.html (0 => 220549)


--- trunk/LayoutTests/http/wpt/beacon/connect-src-beacon-redirect-blocked.sub.html	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/beacon/connect-src-beacon-redirect-blocked.sub.html	2017-08-10 21:51:15 UTC (rev 220549)
@@ -0,0 +1,50 @@
+<!doctype html>
+<html>
+  <head>
+    <meta http-equiv="Content-Security-Policy" content="connect-src 'self'">
+    <meta charset="utf-8">
+    <title>SendBeacon CSP blocking on redirect</title>
+    <script src=""
+    <script src=""
+  </head>
+  <body>
+    <script src=""
+    <script src=""
+    <script>
+var RESOURCES_DIR = "/WebKit/beacon/resources/";
+
+function pollResult(test, id) {
+  var checkUrl = RESOURCES_DIR + "beacon-preflight.py?cmd=get&id=" + id;
+
+  return new Promise(resolve => {
+    step_timeout(test.step_func(() => {
+      fetch(checkUrl).then(response => {
+        response.json().then(body => {
+          resolve(body);
+        });
+      });
+    }), 1000);
+  });
+}
+
+function testCORSPreflightRedirectSuccess(what) {
+  var testBase = get_host_info().HTTP_REMOTE_ORIGIN + RESOURCES_DIR;
+  var id = self.token();
+  var target = encodeURIComponent(testBase + "beacon-preflight.py?allowCors=1&cmd=put&id=" + id);
+
+  // 307 & 308 redirections are the only ones that maintain the POST method.
+  var testUrl = RESOURCES_DIR + "redirect.py?redirect_status=307&location=" + target;
+
+  promise_test(function(test) {
+    assert_true(navigator.sendBeacon(testUrl, what), "SendBeacon Succeeded");
+    return pollResult(test, id) .then(result => {
+      assert_equals(result['preflight'], 0, "Did not receive preflight")
+      assert_equals(result['beacon'], 0, "Did not receive beacon")
+    });
+  }, "Redirect is blocked by CSP");
+}
+
+testCORSPreflightRedirectSuccess("123");
+    </script>
+  </body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (220548 => 220549)


--- trunk/Source/WebCore/ChangeLog	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebCore/ChangeLog	2017-08-10 21:51:15 UTC (rev 220549)
@@ -1,3 +1,38 @@
+2017-08-10  Chris Dumez  <cdu...@apple.com>
+
+        [Beacon] Do connect-src CSP check on redirects as well
+        https://bugs.webkit.org/show_bug.cgi?id=175410
+        <rdar://problem/33815470>
+
+        Reviewed by Youenn Fablet.
+
+        Pass ContentSecurityPolicy object to createPingHandle so that we can send
+        enough data to the NetworkProcess so do CSP checks for Ping loads such
+        as Beacon. For the IPC, we serialize the ContentSecurityPolicy's response
+        headers. Those headers are now cached in ContentSecurityPolicy for
+        performance reasons. CSP headers are rarely updated in practice but
+        sendBeacon() may get called repeatedly for a given document.
+
+        Tests: http/wpt/beacon/connect-src-beacon-redirect-allowed.sub.html
+               http/wpt/beacon/connect-src-beacon-redirect-blocked.sub.html
+
+        * loader/LoaderStrategy.h:
+        * loader/PingLoader.cpp:
+        (WebCore::PingLoader::loadImage):
+        (WebCore::PingLoader::sendPing):
+        (WebCore::PingLoader::sendViolationReport):
+        (WebCore::PingLoader::startPingLoad):
+        * loader/PingLoader.h:
+        * loader/cache/CachedResource.cpp:
+        (WebCore::CachedResource::load):
+        * page/csp/ContentSecurityPolicy.cpp:
+        (WebCore::ContentSecurityPolicy::responseHeaders const):
+        (WebCore::ContentSecurityPolicy::didReceiveHeader):
+        * page/csp/ContentSecurityPolicy.h:
+        * page/csp/ContentSecurityPolicyResponseHeaders.h:
+        (WebCore::ContentSecurityPolicyResponseHeaders::encode const):
+        (WebCore::ContentSecurityPolicyResponseHeaders::decode):
+
 2017-08-09  Yusuke Suzuki  <utatane....@gmail.com>
 
         [WTF] ThreadSpecific should not introduce additional indirection

Modified: trunk/Source/WebCore/loader/LoaderStrategy.h (220548 => 220549)


--- trunk/Source/WebCore/loader/LoaderStrategy.h	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebCore/loader/LoaderStrategy.h	2017-08-10 21:51:15 UTC (rev 220549)
@@ -34,6 +34,7 @@
 namespace WebCore {
 
 class CachedResource;
+class ContentSecurityPolicy;
 class Frame;
 class NetscapePlugInStreamLoader;
 class NetscapePlugInStreamLoaderClient;
@@ -62,7 +63,7 @@
     virtual void suspendPendingRequests() = 0;
     virtual void resumePendingRequests() = 0;
 
-    virtual void createPingHandle(NetworkingContext*, ResourceRequest&, Ref<SecurityOrigin>&& sourceOrigin, const FetchOptions&) = 0;
+    virtual void createPingHandle(NetworkingContext*, ResourceRequest&, Ref<SecurityOrigin>&& sourceOrigin, ContentSecurityPolicy*, const FetchOptions&) = 0;
 
     virtual void storeDerivedDataToCache(const SHA1::Digest& bodyKey, const String& type, const String& partition, WebCore::SharedBuffer&) = 0;
 

Modified: trunk/Source/WebCore/loader/PingLoader.cpp (220548 => 220549)


--- trunk/Source/WebCore/loader/PingLoader.cpp	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebCore/loader/PingLoader.cpp	2017-08-10 21:51:15 UTC (rev 220549)
@@ -103,7 +103,7 @@
         request.setHTTPReferrer(referrer);
     frame.loader().addExtraFieldsToSubresourceRequest(request);
 
-    startPingLoad(frame, request, document.securityOrigin(), ShouldFollowRedirects::Yes);
+    startPingLoad(frame, request, document, ShouldFollowRedirects::Yes);
 }
 
 // http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#hyperlink-auditing
@@ -139,7 +139,7 @@
         }
     }
 
-    startPingLoad(frame, request, sourceOrigin, ShouldFollowRedirects::Yes);
+    startPingLoad(frame, request, document, ShouldFollowRedirects::Yes);
 }
 
 void PingLoader::sendViolationReport(Frame& frame, const URL& reportURL, Ref<FormData>&& report, ViolationReportType reportType)
@@ -176,10 +176,10 @@
     if (!referrer.isEmpty())
         request.setHTTPReferrer(referrer);
 
-    startPingLoad(frame, request, document.securityOrigin(), ShouldFollowRedirects::No);
+    startPingLoad(frame, request, document, ShouldFollowRedirects::No);
 }
 
-void PingLoader::startPingLoad(Frame& frame, ResourceRequest& request, SecurityOrigin& sourceOrigin, ShouldFollowRedirects shouldFollowRedirects)
+void PingLoader::startPingLoad(Frame& frame, ResourceRequest& request, Document& document, ShouldFollowRedirects shouldFollowRedirects)
 {
     unsigned long identifier = frame.page()->progress().createUniqueIdentifier();
     // FIXME: Why activeDocumentLoader? I would have expected documentLoader().
@@ -194,7 +194,8 @@
 
     InspectorInstrumentation::continueAfterPingLoader(frame, identifier, frame.loader().activeDocumentLoader(), request, ResourceResponse());
 
-    platformStrategies()->loaderStrategy()->createPingHandle(frame.loader().networkingContext(), request, sourceOrigin, options);
+    auto* contentSecurityPolicy = document.shouldBypassMainWorldContentSecurityPolicy() ? nullptr : document.contentSecurityPolicy();
+    platformStrategies()->loaderStrategy()->createPingHandle(frame.loader().networkingContext(), request, document.securityOrigin(), contentSecurityPolicy, options);
 }
 
 }

Modified: trunk/Source/WebCore/loader/PingLoader.h (220548 => 220549)


--- trunk/Source/WebCore/loader/PingLoader.h	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebCore/loader/PingLoader.h	2017-08-10 21:51:15 UTC (rev 220549)
@@ -37,11 +37,11 @@
 
 namespace WebCore {
 
+class Document;
 class FormData;
 class Frame;
 class URL;
 class ResourceRequest;
-class SecurityOrigin;
 
 enum class ViolationReportType {
     ContentSecurityPolicy,
@@ -56,7 +56,7 @@
 
 private:
     enum class ShouldFollowRedirects { No, Yes };
-    static void startPingLoad(Frame&, ResourceRequest&, SecurityOrigin& sourceOrigin, ShouldFollowRedirects);
+    static void startPingLoad(Frame&, ResourceRequest&, Document&, ShouldFollowRedirects);
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/loader/cache/CachedResource.cpp (220548 => 220549)


--- trunk/Source/WebCore/loader/cache/CachedResource.cpp	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebCore/loader/cache/CachedResource.cpp	2017-08-10 21:51:15 UTC (rev 220549)
@@ -262,7 +262,10 @@
     // FIXME: We should not special-case Beacon here.
     if (m_options.keepAlive && type() == CachedResource::Beacon) {
         ASSERT(m_origin);
-        platformStrategies()->loaderStrategy()->createPingHandle(frame.loader().networkingContext(), request, *m_origin, m_options);
+        // Beacon is not exposed to workers so it is safe to rely on the document here.
+        auto* document = cachedResourceLoader.document();
+        auto* contentSecurityPolicy = document && !document->shouldBypassMainWorldContentSecurityPolicy() ? document->contentSecurityPolicy() : nullptr;
+        platformStrategies()->loaderStrategy()->createPingHandle(frame.loader().networkingContext(), request, *m_origin, contentSecurityPolicy, m_options);
         return;
     }
 

Modified: trunk/Source/WebCore/page/csp/ContentSecurityPolicy.cpp (220548 => 220549)


--- trunk/Source/WebCore/page/csp/ContentSecurityPolicy.cpp	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebCore/page/csp/ContentSecurityPolicy.cpp	2017-08-10 21:51:15 UTC (rev 220549)
@@ -164,11 +164,14 @@
 
 ContentSecurityPolicyResponseHeaders ContentSecurityPolicy::responseHeaders() const
 {
-    ContentSecurityPolicyResponseHeaders result;
-    result.m_headers.reserveInitialCapacity(m_policies.size());
-    for (auto& policy : m_policies)
-        result.m_headers.uncheckedAppend({ policy->header(), policy->headerType() });
-    return result;
+    if (!m_cachedResponseHeaders) {
+        ContentSecurityPolicyResponseHeaders result;
+        result.m_headers.reserveInitialCapacity(m_policies.size());
+        for (auto& policy : m_policies)
+            result.m_headers.uncheckedAppend({ policy->header(), policy->headerType() });
+        m_cachedResponseHeaders = WTFMove(result);
+    }
+    return *m_cachedResponseHeaders;
 }
 
 void ContentSecurityPolicy::didReceiveHeaders(const ContentSecurityPolicyResponseHeaders& headers, ReportParsingErrors reportParsingErrors)
@@ -188,6 +191,8 @@
         m_hasAPIPolicy = true;
     }
 
+    m_cachedResponseHeaders = std::nullopt;
+
     // RFC2616, section 4.2 specifies that headers appearing multiple times can
     // be combined with a comma. Walk the header string, and parse each comma
     // separated chunk as a separate header.

Modified: trunk/Source/WebCore/page/csp/ContentSecurityPolicy.h (220548 => 220549)


--- trunk/Source/WebCore/page/csp/ContentSecurityPolicy.h	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebCore/page/csp/ContentSecurityPolicy.h	2017-08-10 21:51:15 UTC (rev 220549)
@@ -65,8 +65,8 @@
     WTF_MAKE_FAST_ALLOCATED;
 public:
     explicit ContentSecurityPolicy(ScriptExecutionContext&);
-    explicit ContentSecurityPolicy(const SecurityOrigin&, const Frame* = nullptr);
-    ~ContentSecurityPolicy();
+    WEBCORE_EXPORT explicit ContentSecurityPolicy(const SecurityOrigin&, const Frame* = nullptr);
+    WEBCORE_EXPORT ~ContentSecurityPolicy();
 
     void copyStateFrom(const ContentSecurityPolicy*);
     void copyUpgradeInsecureRequestStateFrom(const ContentSecurityPolicy&);
@@ -79,9 +79,9 @@
         HTTPHeader,
         Inherited,
     };
-    ContentSecurityPolicyResponseHeaders responseHeaders() const;
+    WEBCORE_EXPORT ContentSecurityPolicyResponseHeaders responseHeaders() const;
     enum ReportParsingErrors { No, Yes };
-    void didReceiveHeaders(const ContentSecurityPolicyResponseHeaders&, ReportParsingErrors = ReportParsingErrors::Yes);
+    WEBCORE_EXPORT void didReceiveHeaders(const ContentSecurityPolicyResponseHeaders&, ReportParsingErrors = ReportParsingErrors::Yes);
     void didReceiveHeader(const String&, ContentSecurityPolicyHeaderType, ContentSecurityPolicy::PolicyFrom);
 
     bool allowScriptWithNonce(const String& nonce, bool overrideContentSecurityPolicy = false) const;
@@ -107,7 +107,7 @@
 
     bool allowChildFrameFromSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
     bool allowChildContextFromSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
-    bool allowConnectToSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
+    WEBCORE_EXPORT bool allowConnectToSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
     bool allowFormAction(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
 
     bool allowObjectFromSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
@@ -216,6 +216,7 @@
     OptionSet<ContentSecurityPolicyHashAlgorithm> m_hashAlgorithmsForInlineScripts;
     OptionSet<ContentSecurityPolicyHashAlgorithm> m_hashAlgorithmsForInlineStylesheets;
     HashSet<RefPtr<SecurityOrigin>> m_insecureNavigationRequestsToUpgrade;
+    mutable std::optional<ContentSecurityPolicyResponseHeaders> m_cachedResponseHeaders;
 };
 
 }

Modified: trunk/Source/WebCore/page/csp/ContentSecurityPolicyResponseHeaders.h (220548 => 220549)


--- trunk/Source/WebCore/page/csp/ContentSecurityPolicyResponseHeaders.h	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebCore/page/csp/ContentSecurityPolicyResponseHeaders.h	2017-08-10 21:51:15 UTC (rev 220549)
@@ -42,16 +42,48 @@
 
 class ContentSecurityPolicyResponseHeaders {
 public:
+    ContentSecurityPolicyResponseHeaders() = default;
     explicit ContentSecurityPolicyResponseHeaders(const ResourceResponse&);
 
     ContentSecurityPolicyResponseHeaders isolatedCopy() const;
 
+    template <class Encoder> void encode(Encoder&) const;
+    template <class Decoder> static bool decode(Decoder&, ContentSecurityPolicyResponseHeaders&);
+
 private:
     friend class ContentSecurityPolicy;
 
-    ContentSecurityPolicyResponseHeaders() = default;
-
     Vector<std::pair<String, ContentSecurityPolicyHeaderType>> m_headers;
 };
 
+template <class Encoder>
+void ContentSecurityPolicyResponseHeaders::encode(Encoder& encoder) const
+{
+    encoder << static_cast<uint64_t>(m_headers.size());
+    for (auto& pair : m_headers) {
+        encoder << pair.first;
+        encoder.encodeEnum(pair.second);
+    }
+}
+
+template <class Decoder>
+bool ContentSecurityPolicyResponseHeaders::decode(Decoder& decoder, ContentSecurityPolicyResponseHeaders& headers)
+{
+    uint64_t headersSize;
+    if (!decoder.decode(headersSize))
+        return false;
+    headers.m_headers.reserveCapacity(static_cast<size_t>(headersSize));
+    for (size_t i = 0; i < headersSize; ++i) {
+        String header;
+        if (!decoder.decode(header))
+            return false;
+        ContentSecurityPolicyHeaderType headerType;
+        if (!decoder.decodeEnum(headerType))
+            return false;
+        headers.m_headers.append(std::make_pair(header, headerType));
+    }
+
+    return true;
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebKit/ChangeLog (220548 => 220549)


--- trunk/Source/WebKit/ChangeLog	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebKit/ChangeLog	2017-08-10 21:51:15 UTC (rev 220549)
@@ -1,3 +1,32 @@
+2017-08-10  Chris Dumez  <cdu...@apple.com>
+
+        [Beacon] Do connect-src CSP check on redirects as well
+        https://bugs.webkit.org/show_bug.cgi?id=175410
+        <rdar://problem/33815470>
+
+        Reviewed by Youenn Fablet.
+
+        Pass CSP Response headers to the NetworkProcess via NetworkResourceLoadParameters
+        when doing a PingLoad. This allows PingLoad to do CSP checks (in particular
+        connect-src ones) in case the ping load gets redirected. Those checks need to be
+        done on the NetworkProcess side at this point because there is no guarantee the
+        WebContent process is still around.
+
+        To do the CSP checks, PingLoad lazily reconstructs a ContentSecurityPolicy object
+        from the CSP response headers.
+
+        * NetworkProcess/NetworkResourceLoadParameters.cpp:
+        (WebKit::NetworkResourceLoadParameters::encode const):
+        (WebKit::NetworkResourceLoadParameters::decode):
+        * NetworkProcess/NetworkResourceLoadParameters.h:
+        * NetworkProcess/PingLoad.cpp:
+        (WebKit::PingLoad::willPerformHTTPRedirection):
+        (WebKit::PingLoad::contentSecurityPolicy):
+        * NetworkProcess/PingLoad.h:
+        * WebProcess/Network/WebLoaderStrategy.cpp:
+        (WebKit::WebLoaderStrategy::createPingHandle):
+        * WebProcess/Network/WebLoaderStrategy.h:
+
 2017-08-10  Brian Burg  <bb...@apple.com>
 
         WKPreferences should conform to NSCopying

Modified: trunk/Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.cpp (220548 => 220549)


--- trunk/Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.cpp	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.cpp	2017-08-10 21:51:15 UTC (rev 220549)
@@ -87,6 +87,7 @@
     if (sourceOrigin)
         encoder << SecurityOriginData::fromSecurityOrigin(*sourceOrigin);
     encoder.encodeEnum(mode);
+    encoder << cspResponseHeaders;
 }
 
 bool NetworkResourceLoadParameters::decode(IPC::Decoder& decoder, NetworkResourceLoadParameters& result)
@@ -163,6 +164,8 @@
     }
     if (!decoder.decodeEnum(result.mode))
         return false;
+    if (!decoder.decode(result.cspResponseHeaders))
+        return false;
 
     return true;
 }

Modified: trunk/Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.h (220548 => 220549)


--- trunk/Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.h	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.h	2017-08-10 21:51:15 UTC (rev 220549)
@@ -28,6 +28,7 @@
 
 #include "NetworkLoadParameters.h"
 #include "SandboxExtension.h"
+#include <WebCore/ContentSecurityPolicyResponseHeaders.h>
 #include <WebCore/FetchOptions.h>
 #include <WebCore/ResourceHandle.h>
 #include <WebCore/ResourceLoaderOptions.h>
@@ -57,6 +58,7 @@
     Vector<String> derivedCachedDataTypesToRetrieve;
     RefPtr<WebCore::SecurityOrigin> sourceOrigin;
     WebCore::FetchOptions::Mode mode;
+    std::optional<WebCore::ContentSecurityPolicyResponseHeaders> cspResponseHeaders;
 };
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/NetworkProcess/PingLoad.cpp (220548 => 220549)


--- trunk/Source/WebKit/NetworkProcess/PingLoad.cpp	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebKit/NetworkProcess/PingLoad.cpp	2017-08-10 21:51:15 UTC (rev 220549)
@@ -32,6 +32,7 @@
 #include "Logging.h"
 #include "NetworkCORSPreflightChecker.h"
 #include "SessionTracker.h"
+#include <WebCore/ContentSecurityPolicy.h>
 #include <WebCore/CrossOriginAccessControl.h>
 
 #define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(m_parameters.sessionID.isAlwaysOnLoggingAllowed(), Network, "%p - PingLoad::" fmt, this, ##__VA_ARGS__)
@@ -91,8 +92,17 @@
         completionHandler({ });
         return;
     }
-    // FIXME: Do CSP check.
+
+    if (auto* contentSecurityPolicy = this->contentSecurityPolicy()) {
+        if (!contentSecurityPolicy->allowConnectToSource(request.url(), redirectResponse.isNull() ? ContentSecurityPolicy::RedirectResponseReceived::No : ContentSecurityPolicy::RedirectResponseReceived::Yes)) {
+            RELEASE_LOG_IF_ALLOWED("willPerformHTTPRedirection - Redirect was blocked by CSP");
+            completionHandler({ });
+            return;
+        }
+    }
+
     // FIXME: We should ensure the number of redirects does not exceed 20.
+
     if (!needsCORSPreflight(request)) {
         completionHandler(request);
         return;
@@ -175,6 +185,15 @@
     return !m_isSameOriginRequest || !securityOrigin().canRequest(request.url());
 }
 
+ContentSecurityPolicy* PingLoad::contentSecurityPolicy() const
+{
+    if (!m_contentSecurityPolicy && m_parameters.cspResponseHeaders) {
+        m_contentSecurityPolicy = std::make_unique<ContentSecurityPolicy>(*m_parameters.sourceOrigin);
+        m_contentSecurityPolicy->didReceiveHeaders(*m_parameters.cspResponseHeaders, ContentSecurityPolicy::ReportParsingErrors::No);
+    }
+    return m_contentSecurityPolicy.get();
+}
+
 void PingLoad::doCORSPreflight(const ResourceRequest& request)
 {
     RELEASE_LOG_IF_ALLOWED("doCORSPreflight");

Modified: trunk/Source/WebKit/NetworkProcess/PingLoad.h (220548 => 220549)


--- trunk/Source/WebKit/NetworkProcess/PingLoad.h	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebKit/NetworkProcess/PingLoad.h	2017-08-10 21:51:15 UTC (rev 220549)
@@ -30,6 +30,10 @@
 #include "NetworkDataTask.h"
 #include "NetworkResourceLoadParameters.h"
 
+namespace WebCore {
+class ContentSecurityPolicy;
+}
+
 namespace WebKit {
 
 class NetworkCORSPreflightChecker;
@@ -41,6 +45,8 @@
 private:
     ~PingLoad();
 
+    WebCore::ContentSecurityPolicy* contentSecurityPolicy() const;
+
     void willPerformHTTPRedirection(WebCore::ResourceResponse&&, WebCore::ResourceRequest&&, RedirectCompletionHandler&&) final;
     void didReceiveChallenge(const WebCore::AuthenticationChallenge&, ChallengeCompletionHandler&&) final;
     void didReceiveResponseNetworkSession(WebCore::ResourceResponse&&, ResponseCompletionHandler&&) final;
@@ -64,6 +70,7 @@
     RefPtr<WebCore::SecurityOrigin> m_origin;
     bool m_isSameOriginRequest;
     RedirectCompletionHandler m_redirectHandler;
+    mutable std::unique_ptr<WebCore::ContentSecurityPolicy> m_contentSecurityPolicy;
 };
 
 }

Modified: trunk/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp (220548 => 220549)


--- trunk/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp	2017-08-10 21:51:15 UTC (rev 220549)
@@ -46,6 +46,7 @@
 #include "WebURLSchemeTaskProxy.h"
 #include <WebCore/ApplicationCacheHost.h>
 #include <WebCore/CachedResource.h>
+#include <WebCore/ContentSecurityPolicy.h>
 #include <WebCore/DiagnosticLoggingClient.h>
 #include <WebCore/DiagnosticLoggingKeys.h>
 #include <WebCore/Document.h>
@@ -385,7 +386,7 @@
     }
 }
 
-void WebLoaderStrategy::createPingHandle(NetworkingContext* networkingContext, ResourceRequest& request, Ref<SecurityOrigin>&& sourceOrigin, const FetchOptions& options)
+void WebLoaderStrategy::createPingHandle(NetworkingContext* networkingContext, ResourceRequest& request, Ref<SecurityOrigin>&& sourceOrigin, ContentSecurityPolicy* contentSecurityPolicy, const FetchOptions& options)
 {
     // It's possible that call to createPingHandle might be made during initial empty Document creation before a NetworkingContext exists.
     // It is not clear that we should send ping loads during that process anyways.
@@ -405,6 +406,8 @@
     loadParameters.mode = options.mode;
     loadParameters.shouldFollowRedirects = options.redirect == FetchOptions::Redirect::Follow;
     loadParameters.shouldClearReferrerOnHTTPSToHTTPRedirect = networkingContext->shouldClearReferrerOnHTTPSToHTTPRedirect();
+    if (contentSecurityPolicy)
+        loadParameters.cspResponseHeaders = contentSecurityPolicy->responseHeaders();
 
     WebProcess::singleton().networkConnection().connection().send(Messages::NetworkConnectionToWebProcess::LoadPing(loadParameters), 0);
 }

Modified: trunk/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h (220548 => 220549)


--- trunk/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h	2017-08-10 21:51:15 UTC (rev 220549)
@@ -41,29 +41,29 @@
 class WebURLSchemeTaskProxy;
 typedef uint64_t ResourceLoadIdentifier;
 
-class WebLoaderStrategy : public WebCore::LoaderStrategy {
+class WebLoaderStrategy final : public WebCore::LoaderStrategy {
     WTF_MAKE_NONCOPYABLE(WebLoaderStrategy); WTF_MAKE_FAST_ALLOCATED;
 public:
     WebLoaderStrategy();
-    ~WebLoaderStrategy() override;
+    ~WebLoaderStrategy() final;
     
-    RefPtr<WebCore::SubresourceLoader> loadResource(WebCore::Frame&, WebCore::CachedResource&, const WebCore::ResourceRequest&, const WebCore::ResourceLoaderOptions&) override;
-    void loadResourceSynchronously(WebCore::NetworkingContext*, unsigned long resourceLoadIdentifier, const WebCore::ResourceRequest&, WebCore::StoredCredentials, WebCore::ClientCredentialPolicy, WebCore::ResourceError&, WebCore::ResourceResponse&, Vector<char>& data) override;
+    RefPtr<WebCore::SubresourceLoader> loadResource(WebCore::Frame&, WebCore::CachedResource&, const WebCore::ResourceRequest&, const WebCore::ResourceLoaderOptions&) final;
+    void loadResourceSynchronously(WebCore::NetworkingContext*, unsigned long resourceLoadIdentifier, const WebCore::ResourceRequest&, WebCore::StoredCredentials, WebCore::ClientCredentialPolicy, WebCore::ResourceError&, WebCore::ResourceResponse&, Vector<char>& data) final;
 
-    void remove(WebCore::ResourceLoader*) override;
-    void setDefersLoading(WebCore::ResourceLoader*, bool) override;
-    void crossOriginRedirectReceived(WebCore::ResourceLoader*, const WebCore::URL& redirectURL) override;
+    void remove(WebCore::ResourceLoader*) final;
+    void setDefersLoading(WebCore::ResourceLoader*, bool) final;
+    void crossOriginRedirectReceived(WebCore::ResourceLoader*, const WebCore::URL& redirectURL) final;
     
-    void servePendingRequests(WebCore::ResourceLoadPriority minimumPriority) override;
+    void servePendingRequests(WebCore::ResourceLoadPriority minimumPriority) final;
 
-    void suspendPendingRequests() override;
-    void resumePendingRequests() override;
+    void suspendPendingRequests() final;
+    void resumePendingRequests() final;
 
-    void createPingHandle(WebCore::NetworkingContext*, WebCore::ResourceRequest&, Ref<WebCore::SecurityOrigin>&& sourceOrigin, const WebCore::FetchOptions&) override;
+    void createPingHandle(WebCore::NetworkingContext*, WebCore::ResourceRequest&, Ref<WebCore::SecurityOrigin>&& sourceOrigin, WebCore::ContentSecurityPolicy*, const WebCore::FetchOptions&) final;
 
-    void storeDerivedDataToCache(const SHA1::Digest& bodyHash, const String& type, const String& partition, WebCore::SharedBuffer&) override;
+    void storeDerivedDataToCache(const SHA1::Digest& bodyHash, const String& type, const String& partition, WebCore::SharedBuffer&) final;
 
-    void setCaptureExtraNetworkLoadMetricsEnabled(bool) override;
+    void setCaptureExtraNetworkLoadMetricsEnabled(bool) final;
 
     WebResourceLoader* webResourceLoaderForIdentifier(ResourceLoadIdentifier identifier) const { return m_webResourceLoaders.get(identifier); }
     RefPtr<WebCore::NetscapePlugInStreamLoader> schedulePluginStreamLoad(WebCore::Frame&, WebCore::NetscapePlugInStreamLoaderClient&, const WebCore::ResourceRequest&);

Modified: trunk/Source/WebKitLegacy/ChangeLog (220548 => 220549)


--- trunk/Source/WebKitLegacy/ChangeLog	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebKitLegacy/ChangeLog	2017-08-10 21:51:15 UTC (rev 220549)
@@ -1,3 +1,18 @@
+2017-08-10  Chris Dumez  <cdu...@apple.com>
+
+        [Beacon] Do connect-src CSP check on redirects as well
+        https://bugs.webkit.org/show_bug.cgi?id=175410
+        <rdar://problem/33815470>
+
+        Reviewed by Youenn Fablet.
+
+        Update createPingHandle() to take in ContentSecurityPolicy
+        object in but no behavior change for WK1.
+
+        * WebCoreSupport/WebResourceLoadScheduler.cpp:
+        (WebResourceLoadScheduler::createPingHandle):
+        * WebCoreSupport/WebResourceLoadScheduler.h:
+
 2017-08-08  Chris Dumez  <cdu...@apple.com>
 
         [Beacon] Add support for CORS-preflighting for WK2 / NETWORK_SESSION

Modified: trunk/Source/WebKitLegacy/WebCoreSupport/WebResourceLoadScheduler.cpp (220548 => 220549)


--- trunk/Source/WebKitLegacy/WebCoreSupport/WebResourceLoadScheduler.cpp	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebKitLegacy/WebCoreSupport/WebResourceLoadScheduler.cpp	2017-08-10 21:51:15 UTC (rev 220549)
@@ -363,7 +363,7 @@
     return m_requestsLoading.size() >= (webResourceLoadScheduler().isSerialLoadingEnabled() ? 1 : m_maxRequestsInFlight);
 }
 
-void WebResourceLoadScheduler::createPingHandle(NetworkingContext* networkingContext, ResourceRequest& request, Ref<SecurityOrigin>&&, const FetchOptions& options)
+void WebResourceLoadScheduler::createPingHandle(NetworkingContext* networkingContext, ResourceRequest& request, Ref<SecurityOrigin>&&, WebCore::ContentSecurityPolicy*, const FetchOptions& options)
 {
     // PingHandle manages its own lifetime, deleting itself when its purpose has been fulfilled.
     new PingHandle(networkingContext, request, options.credentials != FetchOptions::Credentials::Omit, PingHandle::UsesAsyncCallbacks::No, options.redirect == FetchOptions::Redirect::Follow);

Modified: trunk/Source/WebKitLegacy/WebCoreSupport/WebResourceLoadScheduler.h (220548 => 220549)


--- trunk/Source/WebKitLegacy/WebCoreSupport/WebResourceLoadScheduler.h	2017-08-10 21:19:51 UTC (rev 220548)
+++ trunk/Source/WebKitLegacy/WebCoreSupport/WebResourceLoadScheduler.h	2017-08-10 21:51:15 UTC (rev 220549)
@@ -59,7 +59,7 @@
     void suspendPendingRequests() override;
     void resumePendingRequests() override;
 
-    void createPingHandle(WebCore::NetworkingContext*, WebCore::ResourceRequest&, Ref<WebCore::SecurityOrigin>&& sourceOrigin, const WebCore::FetchOptions&) override;
+    void createPingHandle(WebCore::NetworkingContext*, WebCore::ResourceRequest&, Ref<WebCore::SecurityOrigin>&& sourceOrigin, WebCore::ContentSecurityPolicy*, const WebCore::FetchOptions&) override;
 
     void storeDerivedDataToCache(const SHA1::Digest&, const String&, const String&, WebCore::SharedBuffer&) override { }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to