Validate Cross-Origin-Resource-Policy for resources cached in the MemoryCache
authoryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Jun 2018 17:30:02 +0000 (17:30 +0000)
committeryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Jun 2018 17:30:02 +0000 (17:30 +0000)
https://bugs.webkit.org/show_bug.cgi?id=186639
<rdar://problem/41106984>

Reviewed by Geoffrey Garen.

Source/WebCore:

Add a method to check CORP.
Make use of it to validate any memory cached resource.
Whitelist CORP header so that it is not filtered out by Network Process.

Test: http/wpt/cross-origin-resource-policy/image-in-iframe-loads.html

* loader/CrossOriginAccessControl.cpp:
(WebCore::shouldCrossOriginResourcePolicyCancelLoad):
(WebCore::validateCrossOriginResourcePolicy):
* loader/CrossOriginAccessControl.h:
* loader/cache/CachedResourceLoader.cpp:
(WebCore::CachedResourceLoader::requestResource):
* platform/network/ResourceResponseBase.cpp:
(WebCore::isSafeRedirectionResponseHeader):
(WebCore::isSafeCrossOriginResponseHeader):

Source/WebKit:

Make use of WebCore method to check CORP.

* NetworkProcess/NetworkLoadChecker.cpp:
(WebKit::NetworkLoadChecker::validateResponse):
* NetworkProcess/NetworkLoadChecker.h:

LayoutTests:

* http/wpt/cross-origin-resource-policy/image-in-iframe-loads-expected.txt: Added.
* http/wpt/cross-origin-resource-policy/image-in-iframe-loads.html: Added.
* http/wpt/cross-origin-resource-policy/resources/iframeImage.html: Added.
* http/wpt/cross-origin-resource-policy/resources/image.py:
(main):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@232933 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
LayoutTests/ChangeLog
LayoutTests/http/wpt/cross-origin-resource-policy/image-in-iframe-loads-expected.txt [new file with mode: 0644]
LayoutTests/http/wpt/cross-origin-resource-policy/image-in-iframe-loads.html [new file with mode: 0644]
LayoutTests/http/wpt/cross-origin-resource-policy/resources/iframeImage.html [new file with mode: 0644]
LayoutTests/http/wpt/cross-origin-resource-policy/resources/image.py
Source/WebCore/ChangeLog
Source/WebCore/loader/CrossOriginAccessControl.cpp
Source/WebCore/loader/CrossOriginAccessControl.h
Source/WebCore/loader/cache/CachedResourceLoader.cpp
Source/WebCore/platform/network/ResourceResponseBase.cpp
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkLoadChecker.cpp
Source/WebKit/NetworkProcess/NetworkLoadChecker.h

index 608fbc5..857e935 100644 (file)
@@ -1,3 +1,17 @@
+2018-06-18  Youenn Fablet  <youenn@apple.com>
+
+        Validate Cross-Origin-Resource-Policy for resources cached in the MemoryCache
+        https://bugs.webkit.org/show_bug.cgi?id=186639
+        <rdar://problem/41106984>
+
+        Reviewed by Geoffrey Garen.
+
+        * http/wpt/cross-origin-resource-policy/image-in-iframe-loads-expected.txt: Added.
+        * http/wpt/cross-origin-resource-policy/image-in-iframe-loads.html: Added.
+        * http/wpt/cross-origin-resource-policy/resources/iframeImage.html: Added.
+        * http/wpt/cross-origin-resource-policy/resources/image.py:
+        (main):
+
 2018-06-18  Zan Dobersek  <zdobersek@igalia.com>
 
         Unreviewed WPE gardening. Manage the current set of CSS3 Filters and
diff --git a/LayoutTests/http/wpt/cross-origin-resource-policy/image-in-iframe-loads-expected.txt b/LayoutTests/http/wpt/cross-origin-resource-policy/image-in-iframe-loads-expected.txt
new file mode 100644 (file)
index 0000000..886daf8
--- /dev/null
@@ -0,0 +1,4 @@
+  
+
+PASS Ensure CORP checks in case image is cached 
+
diff --git a/LayoutTests/http/wpt/cross-origin-resource-policy/image-in-iframe-loads.html b/LayoutTests/http/wpt/cross-origin-resource-policy/image-in-iframe-loads.html
new file mode 100644 (file)
index 0000000..d6f221d
--- /dev/null
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/common/get-host-info.sub.js"></script>
+</head>
+<body>
+    <script>
+const host = get_host_info();
+const remoteBaseURL = host.HTTP_REMOTE_ORIGIN + window.location.pathname.replace(/\/[^\/]*$/, '/') ;
+const localBaseURL = host.HTTP_ORIGIN + window.location.pathname.replace(/\/[^\/]*$/, '/') ;
+
+function with_iframe(url) {
+  return new Promise(function(resolve) {
+      var frame = document.createElement('iframe');
+      frame.src = url;
+      frame.onload = function() { resolve(frame); };
+      document.body.appendChild(frame);
+    });
+}
+
+promise_test(async() => {
+    let message = new Promise((resolve) => {
+        window.addEventListener("message", (event) => { resolve(event.data) });
+    });
+    await with_iframe(localBaseURL + "/resources/iframeImage.html");
+    assert_equals(await message, "ok", "loading same origin image should succeed");
+
+    message = new Promise((resolve) => {
+        window.addEventListener("message", (event) => { resolve(event.data) });
+    });
+    await with_iframe(remoteBaseURL + "/resources/iframeImage.html");
+    assert_equals(await message, "ko", "loading not same origin image should succeed");
+}, "Ensure CORP checks in case image is cached");
+    </script>
+</body>
+</html>
diff --git a/LayoutTests/http/wpt/cross-origin-resource-policy/resources/iframeImage.html b/LayoutTests/http/wpt/cross-origin-resource-policy/resources/iframeImage.html
new file mode 100644 (file)
index 0000000..7303288
--- /dev/null
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <div id="testDiv"></div>
+    <h3>The iframe making an image load.</h3>
+    <script src="/common/get-host-info.sub.js"></script>
+    <script>
+const host = get_host_info();
+const baseURL = host.HTTP_ORIGIN + window.location.pathname.replace(/\/[^\/]*$/, '/') ;
+const ok = true;
+const ko = false;
+
+const img = new Image();
+img.src = baseURL + "image.py?corp=same-origin&cached";
+img.onload = () => { parent.postMessage("ok", "*") };
+img.onerror = () => { parent.postMessage("ko", "*") };
+testDiv.appendChild(img);
+    </script>
+</body>
+</html>
index ba61981..e28e5b3 100644 (file)
@@ -8,6 +8,9 @@ def main(request, response):
     response.add_required_headers = False
     response.writer.write_status(200)
 
+    if 'cached' in request.GET:
+        response.writer.write_header("Cache-Control", "max-age=600000")
+
     if 'corp' in request.GET:
         response.writer.write_header("cross-origin-resource-policy", request.GET['corp'])
     if 'acao' in request.GET:
index d45797d..1ef4403 100644 (file)
@@ -1,3 +1,27 @@
+2018-06-18  Youenn Fablet  <youenn@apple.com>
+
+        Validate Cross-Origin-Resource-Policy for resources cached in the MemoryCache
+        https://bugs.webkit.org/show_bug.cgi?id=186639
+        <rdar://problem/41106984>
+
+        Reviewed by Geoffrey Garen.
+
+        Add a method to check CORP.
+        Make use of it to validate any memory cached resource.
+        Whitelist CORP header so that it is not filtered out by Network Process.
+
+        Test: http/wpt/cross-origin-resource-policy/image-in-iframe-loads.html
+
+        * loader/CrossOriginAccessControl.cpp:
+        (WebCore::shouldCrossOriginResourcePolicyCancelLoad):
+        (WebCore::validateCrossOriginResourcePolicy):
+        * loader/CrossOriginAccessControl.h:
+        * loader/cache/CachedResourceLoader.cpp:
+        (WebCore::CachedResourceLoader::requestResource):
+        * platform/network/ResourceResponseBase.cpp:
+        (WebCore::isSafeRedirectionResponseHeader):
+        (WebCore::isSafeCrossOriginResponseHeader):
+
 2018-06-18  Carlos Alberto Lopez Perez  <clopez@igalia.com>
 
         [WTF] Remove workarounds needed to support libstdc++-4
index 68804f2..1e026b6 100644 (file)
@@ -208,4 +208,34 @@ bool validatePreflightResponse(const ResourceRequest& request, const ResourceRes
     return true;
 }
 
+static inline bool shouldCrossOriginResourcePolicyCancelLoad(const SecurityOrigin& origin, const ResourceResponse& response)
+{
+    if (origin.canRequest(response.url()))
+        return false;
+
+    auto policy = parseCrossOriginResourcePolicyHeader(response.httpHeaderField(HTTPHeaderName::CrossOriginResourcePolicy));
+    switch (policy) {
+    case CrossOriginResourcePolicy::None:
+    case CrossOriginResourcePolicy::Invalid:
+        return false;
+    case CrossOriginResourcePolicy::SameOrigin:
+        return true;
+    case CrossOriginResourcePolicy::SameSite: {
+#if ENABLE(PUBLIC_SUFFIX_LIST)
+        return origin.isUnique() || !registrableDomainsAreEqual(response.url(), ResourceRequest::partitionName(origin.host()));
+#else
+        return true;
+#endif
+    }}
+
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+std::optional<ResourceError> validateCrossOriginResourcePolicy(const SecurityOrigin& origin, const URL& requestURL, const ResourceResponse& response)
+{
+    if (shouldCrossOriginResourcePolicyCancelLoad(origin, response))
+        return ResourceError { errorDomainWebKitInternal, 0, requestURL, makeString("Cancelled load to ", response.url().stringCenterEllipsizedToLength(), " because it violates the resource's Cross-Origin-Resource-Policy response header."), ResourceError::Type::AccessControl };
+    return std::nullopt;
+}
+
 } // namespace WebCore
index 8b6fb30..2c6754b 100644 (file)
@@ -34,6 +34,7 @@
 namespace WebCore {
 
 class HTTPHeaderMap;
+class ResourceError;
 class ResourceRequest;
 class ResourceResponse;
 class SecurityOrigin;
@@ -56,4 +57,6 @@ WEBCORE_EXPORT void cleanHTTPRequestHeadersForAccessControl(ResourceRequest&, co
 WEBCORE_EXPORT bool passesAccessControlCheck(const ResourceResponse&, StoredCredentialsPolicy, SecurityOrigin&, String& errorDescription);
 WEBCORE_EXPORT bool validatePreflightResponse(const ResourceRequest&, const ResourceResponse&, StoredCredentialsPolicy, SecurityOrigin&, String& errorDescription);
 
+WEBCORE_EXPORT std::optional<ResourceError> validateCrossOriginResourcePolicy(const SecurityOrigin&, const URL&, const ResourceResponse&);
+
 } // namespace WebCore
index a703e5e..6c63451 100644 (file)
@@ -893,6 +893,10 @@ ResourceErrorOr<CachedResourceHandle<CachedResource>> CachedResourceLoader::requ
         break;
     case Use:
         ASSERT(resource);
+        if (request.options().mode == FetchOptions::Mode::NoCors) {
+            if (auto error = validateCrossOriginResourcePolicy(*request.origin(), request.resourceRequest().url(), resource->response()))
+                return makeUnexpected(WTFMove(*error));
+        }
         if (shouldUpdateCachedResourceWithCurrentRequest(*resource, request)) {
             resource = updateCachedResourceWithCurrentRequest(*resource, WTFMove(request));
             if (resource->status() != CachedResource::Status::Cached)
index 4196783..50d97c7 100644 (file)
@@ -333,6 +333,7 @@ static bool isSafeRedirectionResponseHeader(HTTPHeaderName name)
         || name == HTTPHeaderName::AccessControlAllowOrigin
         || name == HTTPHeaderName::AccessControlExposeHeaders
         || name == HTTPHeaderName::AccessControlMaxAge
+        || name == HTTPHeaderName::CrossOriginResourcePolicy
         || name == HTTPHeaderName::TimingAllowOrigin;
 }
 
@@ -358,6 +359,7 @@ static bool isSafeCrossOriginResponseHeader(HTTPHeaderName name)
         || name == HTTPHeaderName::ContentSecurityPolicy
         || name == HTTPHeaderName::ContentSecurityPolicyReportOnly
         || name == HTTPHeaderName::ContentType
+        || name == HTTPHeaderName::CrossOriginResourcePolicy
         || name == HTTPHeaderName::Date
         || name == HTTPHeaderName::ETag
         || name == HTTPHeaderName::Expires
index d2f6424..624928f 100644 (file)
@@ -1,3 +1,17 @@
+2018-06-18  Youenn Fablet  <youenn@apple.com>
+
+        Validate Cross-Origin-Resource-Policy for resources cached in the MemoryCache
+        https://bugs.webkit.org/show_bug.cgi?id=186639
+        <rdar://problem/41106984>
+
+        Reviewed by Geoffrey Garen.
+
+        Make use of WebCore method to check CORP.
+
+        * NetworkProcess/NetworkLoadChecker.cpp:
+        (WebKit::NetworkLoadChecker::validateResponse):
+        * NetworkProcess/NetworkLoadChecker.h:
+
 2018-06-18  Karl Leplat  <karl.leplat_ext@softathome.com>
 
         [Threaded paintingEngine] Fix rendering glitches
index 7ab89e8..ed2a3ec 100644 (file)
@@ -131,29 +131,6 @@ void NetworkLoadChecker::checkRedirection(ResourceResponse& redirectResponse, Re
     checkRequest(WTFMove(request), WTFMove(handler));
 }
 
-bool NetworkLoadChecker::shouldCrossOriginResourcePolicyPolicyCancelLoad(const ResourceResponse& response)
-{
-    if (m_origin->canRequest(response.url()))
-        return false;
-
-    auto policy = parseCrossOriginResourcePolicyHeader(response.httpHeaderField(HTTPHeaderName::CrossOriginResourcePolicy));
-    switch (policy) {
-    case CrossOriginResourcePolicy::None:
-    case CrossOriginResourcePolicy::Invalid:
-        return false;
-    case CrossOriginResourcePolicy::SameOrigin:
-        return true;
-    case CrossOriginResourcePolicy::SameSite: {
-#if ENABLE(PUBLIC_SUFFIX_LIST)
-        return m_origin->isUnique() || !registrableDomainsAreEqual(response.url(), ResourceRequest::partitionName(m_origin->host()));
-#else
-        return true;
-#endif
-    }}
-
-    RELEASE_ASSERT_NOT_REACHED();
-}
-
 ResourceError NetworkLoadChecker::validateResponse(ResourceResponse& response)
 {
     if (m_redirectCount)
@@ -170,8 +147,9 @@ ResourceError NetworkLoadChecker::validateResponse(ResourceResponse& response)
     }
 
     if (m_options.mode == FetchOptions::Mode::NoCors) {
-        if (shouldCrossOriginResourcePolicyPolicyCancelLoad(response))
-            return ResourceError { errorDomainWebKitInternal, 0, m_url, makeString("Cancelled load to ", response.url().stringCenterEllipsizedToLength(), " because it violates the resource's Cross-Origin-Resource-Policy response header."), ResourceError::Type::AccessControl };
+        if (auto error = validateCrossOriginResourcePolicy(*m_origin, m_url, response))
+            return WTFMove(*error);
+
         response.setTainting(ResourceResponse::Tainting::Opaque);
         return { };
     }
index 1442639..e399881 100644 (file)
@@ -108,8 +108,6 @@ private:
     uint64_t m_webFrameID;
     ResourceLoadIdentifier m_loadIdentifier;
 
-    bool shouldCrossOriginResourcePolicyPolicyCancelLoad(const WebCore::ResourceResponse&);
-
     WebCore::FetchOptions m_options;
     WebCore::StoredCredentialsPolicy m_storedCredentialsPolicy;
     PAL::SessionID m_sessionID;