Check X-Frame-Options and CSP frame-ancestors in network process
authordbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 8 May 2018 05:02:52 +0000 (05:02 +0000)
committerdbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 8 May 2018 05:02:52 +0000 (05:02 +0000)
https://bugs.webkit.org/show_bug.cgi?id=185410
<rdar://problem/37733934>

Reviewed by Ryosuke Niwa.

Source/JavaScriptCore:

Add enum traits for MessageSource and MessageLevel so that we can encode and decode them for IPC.

* runtime/ConsoleTypes.h:

Source/WebCore:

* WebCore.xcodeproj/project.pbxproj: Make PingLoader.h a private header so that we can include it in WebKit.
* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::responseReceived): Only check CSP frame-ancestors and X-Frame-Options here if
we are not checking them in the NetworkProcess and HTTP response access is restricted. I code is otherwise kept
unchanged. There may be opportunities to clean this code up more and share more of it. We should look into this
in subsequent bugs.
* loader/DocumentLoader.h: Change visibility of stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied() from
private to public and export it so that we can call it from the WebKit.
* loader/PingLoader.h:
* page/Settings.yaml: Add a new setting called networkProcessCSPFrameAncestorsCheckingEnabled (defaults: false)
and is hardcoded in WebPage.cpp to be enabled. This setting is used to determine if we will be using the NetworkProcess.
Ideally we wouldn't have this setting and just key off RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess().
However RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess() is always enabled in WebKit Legacy
at the time of writing (why?). And, strangely, RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess()
is conditionally enabled in WebKit. For now, we add a new setting, networkProcessCSPFrameAncestorsCheckingEnabled,
to determine if CSP checking should be performed in NetworkProcess. For checking to actually happen in NetworkProcess
and not in DocumentLoader::responseReceived() RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess()
will also need to be enabled.
* page/csp/ContentSecurityPolicy.cpp:
(WebCore::ContentSecurityPolicy::allowFrameAncestors const): Added a variant that takes a vector of ancestor origins.
* page/csp/ContentSecurityPolicy.h:
* page/csp/ContentSecurityPolicyDirectiveList.cpp:
(WebCore::checkFrameAncestors): Ditto.
(WebCore::ContentSecurityPolicyDirectiveList::violatedDirectiveForFrameAncestorOrigins const): Ditto.
* page/csp/ContentSecurityPolicyDirectiveList.h: Export constructor so that we can invoke it from NetworkResourceLoader::shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions().
* page/csp/ContentSecurityPolicyResponseHeaders.h:
* platform/network/HTTPParsers.h: Export XFrameOptionsDisposition() so that we can use in WebKit.

Source/WebKit:

* NetworkProcess/NetworkResourceLoadParameters.cpp:
(WebKit::NetworkResourceLoadParameters::encode const): Always encode the frame ancestor origins.
(WebKit::NetworkResourceLoadParameters::decode): Always decode the frame ancestor origins.
* NetworkProcess/NetworkResourceLoader.cpp:
(WebKit::NetworkResourceLoader::shouldInterruptLoadForXFrameOptions): Added.
(WebKit::NetworkResourceLoader::shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions): Added.
(WebKit::NetworkResourceLoader::didReceiveResponse): Check if the load needs to be interrupted due
to a violation of the CSP frame-ancestors directive or X-Frame-Options. If there is a violation
then stop the load.
(WebKit::NetworkResourceLoader::didRetrieveCacheEntry): Ditto.
(NetworkResourceLoader::addConsoleMessage): Added.
(NetworkResourceLoader::sendCSPViolationReport): Added.
* NetworkProcess/NetworkResourceLoader.h:
* Scripts/webkit/messages.py: Teach the generator about data types MessageLevel and MessageSource
as they are both defined in file JavaScriptCore/ConsoleTypes.h as opposed to independent headers.
Also tell the generator that these types should not be forward declared so that we can use these
types without their JSC:: prefix in WebPage.messages.in.
* WebProcess/Network/NetworkProcessConnection.cpp:
(WebKit::NetworkProcessConnection::didReceiveMessage): Route WebPage messages to the appropriate
web page.
* WebProcess/Network/WebLoaderStrategy.cpp:
(WebKit::WebLoaderStrategy::scheduleLoadFromNetworkProcess): Added message StopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied.
* WebProcess/Network/WebResourceLoader.cpp:
(WebKit::WebResourceLoader::stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied): Added.
* WebProcess/Network/WebResourceLoader.h:
* WebProcess/Network/WebResourceLoader.messages.in:
* WebProcess/WebPage/WebFrame.cpp:
(WebKit::WebFrame::addConsoleMessage):
* WebProcess/WebPage/WebFrame.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::addConsoleMessage): Added.
(WebKit::WebPage::sendCSPViolationReport): Added.
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in: Add messages AddConsoleMessage and SendCSPViolationReport
for adding a console message to Web Inspector and sending a CSP report, respectively.

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

29 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/ConsoleTypes.h
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/loader/DocumentLoader.cpp
Source/WebCore/loader/DocumentLoader.h
Source/WebCore/loader/PingLoader.h
Source/WebCore/page/Settings.yaml
Source/WebCore/page/csp/ContentSecurityPolicy.cpp
Source/WebCore/page/csp/ContentSecurityPolicy.h
Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.cpp
Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.h
Source/WebCore/page/csp/ContentSecurityPolicyResponseHeaders.h
Source/WebCore/platform/network/HTTPParsers.h
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.cpp
Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp
Source/WebKit/NetworkProcess/NetworkResourceLoader.h
Source/WebKit/Scripts/webkit/messages.py
Source/WebKit/WebProcess/Network/NetworkProcessConnection.cpp
Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp
Source/WebKit/WebProcess/Network/WebResourceLoader.cpp
Source/WebKit/WebProcess/Network/WebResourceLoader.h
Source/WebKit/WebProcess/Network/WebResourceLoader.messages.in
Source/WebKit/WebProcess/WebPage/WebFrame.cpp
Source/WebKit/WebProcess/WebPage/WebFrame.h
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/WebPage.messages.in

index 12cb95a..e69a3cf 100644 (file)
@@ -1,3 +1,15 @@
+2018-05-07  Daniel Bates  <dabates@apple.com>
+
+        Check X-Frame-Options and CSP frame-ancestors in network process
+        https://bugs.webkit.org/show_bug.cgi?id=185410
+        <rdar://problem/37733934>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add enum traits for MessageSource and MessageLevel so that we can encode and decode them for IPC.
+
+        * runtime/ConsoleTypes.h:
+
 2018-05-07  Saam Barati  <sbarati@apple.com>
 
         Make a compact version of VariableEnvironment that UnlinkedFunctionExecutable stores and hash-cons these compact environments as we make them
index 7ca2fe7..3dfec02 100644 (file)
@@ -25,6 +25,8 @@
 
 #pragma once
 
+#include <wtf/EnumTraits.h>
+
 namespace JSC {
 
 enum class MessageSource {
@@ -69,6 +71,40 @@ enum class MessageLevel {
 
 } // namespace JSC
 
+namespace WTF {
+
+template<> struct EnumTraits<JSC::MessageSource> {
+    using values = EnumValues<
+        JSC::MessageSource,
+        JSC::MessageSource::XML,
+        JSC::MessageSource::JS,
+        JSC::MessageSource::Network,
+        JSC::MessageSource::ConsoleAPI,
+        JSC::MessageSource::Storage,
+        JSC::MessageSource::AppCache,
+        JSC::MessageSource::Rendering,
+        JSC::MessageSource::CSS,
+        JSC::MessageSource::Security,
+        JSC::MessageSource::ContentBlocker,
+        JSC::MessageSource::Other,
+        JSC::MessageSource::Media,
+        JSC::MessageSource::WebRTC
+    >;
+};
+
+template<> struct EnumTraits<JSC::MessageLevel> {
+    using values = EnumValues<
+        JSC::MessageLevel,
+        JSC::MessageLevel::Log,
+        JSC::MessageLevel::Warning,
+        JSC::MessageLevel::Error,
+        JSC::MessageLevel::Debug,
+        JSC::MessageLevel::Info
+    >;
+};
+
+} // namespace WTF
+
 using JSC::MessageSource;
 using JSC::MessageType;
 using JSC::MessageLevel;
index 88e5902..fa619a3 100644 (file)
@@ -1,5 +1,41 @@
 2018-05-07  Daniel Bates  <dabates@apple.com>
 
+        Check X-Frame-Options and CSP frame-ancestors in network process
+        https://bugs.webkit.org/show_bug.cgi?id=185410
+        <rdar://problem/37733934>
+
+        Reviewed by Ryosuke Niwa.
+
+        * WebCore.xcodeproj/project.pbxproj: Make PingLoader.h a private header so that we can include it in WebKit.
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::responseReceived): Only check CSP frame-ancestors and X-Frame-Options here if
+        we are not checking them in the NetworkProcess and HTTP response access is restricted. I code is otherwise kept
+        unchanged. There may be opportunities to clean this code up more and share more of it. We should look into this
+        in subsequent bugs.
+        * loader/DocumentLoader.h: Change visibility of stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied() from
+        private to public and export it so that we can call it from the WebKit.
+        * loader/PingLoader.h:
+        * page/Settings.yaml: Add a new setting called networkProcessCSPFrameAncestorsCheckingEnabled (defaults: false)
+        and is hardcoded in WebPage.cpp to be enabled. This setting is used to determine if we will be using the NetworkProcess.
+        Ideally we wouldn't have this setting and just key off RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess().
+        However RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess() is always enabled in WebKit Legacy
+        at the time of writing (why?). And, strangely, RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess()
+        is conditionally enabled in WebKit. For now, we add a new setting, networkProcessCSPFrameAncestorsCheckingEnabled,
+        to determine if CSP checking should be performed in NetworkProcess. For checking to actually happen in NetworkProcess
+        and not in DocumentLoader::responseReceived() RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess()
+        will also need to be enabled.
+        * page/csp/ContentSecurityPolicy.cpp:
+        (WebCore::ContentSecurityPolicy::allowFrameAncestors const): Added a variant that takes a vector of ancestor origins.
+        * page/csp/ContentSecurityPolicy.h:
+        * page/csp/ContentSecurityPolicyDirectiveList.cpp:
+        (WebCore::checkFrameAncestors): Ditto.
+        (WebCore::ContentSecurityPolicyDirectiveList::violatedDirectiveForFrameAncestorOrigins const): Ditto.
+        * page/csp/ContentSecurityPolicyDirectiveList.h: Export constructor so that we can invoke it from NetworkResourceLoader::shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions().
+        * page/csp/ContentSecurityPolicyResponseHeaders.h:
+        * platform/network/HTTPParsers.h: Export XFrameOptionsDisposition() so that we can use in WebKit.
+
+2018-05-07  Daniel Bates  <dabates@apple.com>
+
         Abstract logic to log console messages and send CSP violation reports into a client
         https://bugs.webkit.org/show_bug.cgi?id=185393
         <rdar://problem/40036053>
index f9bdb8f..ef16855 100644 (file)
                D0BC54491443AC4A00E105DA /* CachedStyleSheetClient.h in Headers */ = {isa = PBXBuildFile; fileRef = D0BC54481443AC4A00E105DA /* CachedStyleSheetClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
                D0BD4F5D1408850F006839B6 /* DictationCommandIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = D0BD4F5B1408850F006839B6 /* DictationCommandIOS.h */; };
                D0EDA775143E303C0028E383 /* CachedRawResource.h in Headers */ = {isa = PBXBuildFile; fileRef = D0EDA773143E303C0028E383 /* CachedRawResource.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               D0FF2A5E11F8C45A007E74E0 /* PingLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = D0FF2A5C11F8C45A007E74E0 /* PingLoader.h */; };
+               D0FF2A5E11F8C45A007E74E0 /* PingLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = D0FF2A5C11F8C45A007E74E0 /* PingLoader.h */; settings = {ATTRIBUTES = (Private, ); }; };
                D302754A12A5FE84004BD828 /* RenderDetailsMarker.h in Headers */ = {isa = PBXBuildFile; fileRef = D302754612A5FE84004BD828 /* RenderDetailsMarker.h */; };
                D359D78A129CA2710006E5D2 /* HTMLDetailsElement.h in Headers */ = {isa = PBXBuildFile; fileRef = D359D787129CA2710006E5D2 /* HTMLDetailsElement.h */; };
                D359D8BF129CA55C0006E5D2 /* JSHTMLDetailsElement.h in Headers */ = {isa = PBXBuildFile; fileRef = D359D8BD129CA55C0006E5D2 /* JSHTMLDetailsElement.h */; };
                                A89943280B42338800D7C802 /* BitmapImage.h in Headers */,
                                976D6C79122B8A3D001FD1F7 /* Blob.h in Headers */,
                                976D6C7C122B8A3D001FD1F7 /* BlobBuilder.h in Headers */,
-                               CE5FA255209E48C50051D700 /* ContentSecurityPolicyClient.h in Headers */,
                                A15D75161E68F7C800A35FBC /* BlobCallback.h in Headers */,
                                2EDEF1F4121B0EFC00726DB2 /* BlobData.h in Headers */,
                                E1D31CDD19196020001005A3 /* BlobDataFileReference.h in Headers */,
                                A149786F1ABAF33800CEF7E4 /* ContentFilter.h in Headers */,
                                A14090FD1AA51E480091191A /* ContentFilterUnblockHandler.h in Headers */,
                                97C471DC12F925BD0086354B /* ContentSecurityPolicy.h in Headers */,
+                               CE5FA255209E48C50051D700 /* ContentSecurityPolicyClient.h in Headers */,
                                CE799FA41C6A503A0097B518 /* ContentSecurityPolicyDirective.h in Headers */,
                                CE799F9C1C6A4BCD0097B518 /* ContentSecurityPolicyDirectiveList.h in Headers */,
                                CE2849871CA360DF00B4A57F /* ContentSecurityPolicyDirectiveNames.h in Headers */,
index 954ba77..04b34e5 100644 (file)
@@ -766,26 +766,27 @@ void DocumentLoader::responseReceived(const ResourceResponse& response, Completi
     ASSERT(m_identifierForLoadWithoutResourceLoader || m_mainResource);
     unsigned long identifier = m_identifierForLoadWithoutResourceLoader ? m_identifierForLoadWithoutResourceLoader : m_mainResource->identifier();
     ASSERT(identifier);
-    
-    auto url = response.url();
-
-    ContentSecurityPolicy contentSecurityPolicy(URL { url }, this);
-    contentSecurityPolicy.didReceiveHeaders(ContentSecurityPolicyResponseHeaders { response }, m_request.httpReferrer());
-    if (!contentSecurityPolicy.allowFrameAncestors(*m_frame, url)) {
-        stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied(identifier, response);
-        return;
-    }
 
-    const auto& commonHeaders = response.httpHeaderFields().commonHeaders();
-    auto it = commonHeaders.find(HTTPHeaderName::XFrameOptions);
-    if (it != commonHeaders.end()) {
-        String content = it->value;
-        if (frameLoader()->shouldInterruptLoadForXFrameOptions(content, url, identifier)) {
-            String message = "Refused to display '" + url.stringCenterEllipsizedToLength() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'.";
-            m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message, identifier);
+    if (!m_frame->settings().networkProcessCSPFrameAncestorsCheckingEnabled() || !RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess()) {
+        auto url = response.url();
+        ContentSecurityPolicy contentSecurityPolicy(URL { url }, this);
+        contentSecurityPolicy.didReceiveHeaders(ContentSecurityPolicyResponseHeaders { response }, m_request.httpReferrer());
+        if (!contentSecurityPolicy.allowFrameAncestors(*m_frame, url)) {
             stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied(identifier, response);
             return;
         }
+
+        const auto& commonHeaders = response.httpHeaderFields().commonHeaders();
+        auto it = commonHeaders.find(HTTPHeaderName::XFrameOptions);
+        if (it != commonHeaders.end()) {
+            String content = it->value;
+            if (frameLoader()->shouldInterruptLoadForXFrameOptions(content, url, identifier)) {
+                String message = "Refused to display '" + url.stringCenterEllipsizedToLength() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'.";
+                m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message, identifier);
+                stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied(identifier, response);
+                return;
+            }
+        }
     }
 
     // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
index 00f6dca..071ef64 100644 (file)
@@ -253,6 +253,7 @@ public:
 
     void stopLoadingPlugIns();
     void stopLoadingSubresources();
+    WEBCORE_EXPORT void stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied(unsigned long identifier, const ResourceResponse&);
 
     bool userContentExtensionsEnabled() const { return m_userContentExtensionsEnabled; }
     void setUserContentExtensionsEnabled(bool enabled) { m_userContentExtensionsEnabled = enabled; }
@@ -384,8 +385,6 @@ private:
     void stopLoadingForPolicyChange();
     ResourceError interruptedForPolicyChangeError() const;
 
-    void stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied(unsigned long identifier, const ResourceResponse&);
-
 #if HAVE(RUNLOOP_TIMER)
     typedef RunLoopTimer<DocumentLoader> DocumentLoaderTimer;
 #else
index 175a470..15489dc 100644 (file)
@@ -52,7 +52,7 @@ class PingLoader {
 public:
     static void loadImage(Frame&, const URL&);
     static void sendPing(Frame&, const URL& pingURL, const URL& destinationURL);
-    static void sendViolationReport(Frame&, const URL& reportURL, Ref<FormData>&& report, ViolationReportType);
+    WEBCORE_EXPORT static void sendViolationReport(Frame&, const URL& reportURL, Ref<FormData>&& report, ViolationReportType);
 
 private:
     enum class ShouldFollowRedirects { No, Yes };
index e2e4c7c..5a2ca70 100644 (file)
@@ -313,6 +313,8 @@ forceUpdateScrollbarsOnMainThreadForPerformanceTesting:
   initial: false
 notificationsEnabled:
   initial: true
+networkProcessCSPFrameAncestorsCheckingEnabled:
+  initial: false
 
 # Some apps needs isLoadingInAPISense to account for active subresource loaders.
 needsIsLoadingInAPISenseQuirk:
index 8d910be..ce45806 100644 (file)
@@ -489,6 +489,23 @@ bool ContentSecurityPolicy::allowFrameAncestors(const Frame& frame, const URL& u
     return allPoliciesAllow(WTFMove(handleViolatedDirective), &ContentSecurityPolicyDirectiveList::violatedDirectiveForFrameAncestor, frame);
 }
 
+bool ContentSecurityPolicy::allowFrameAncestors(const Vector<RefPtr<SecurityOrigin>>& ancestorOrigins, const URL& url, bool overrideContentSecurityPolicy) const
+{
+    if (overrideContentSecurityPolicy)
+        return true;
+    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!ancestorOrigins.isEmpty());
+    bool isTopLevelFrame = ancestorOrigins.size() == 1;
+    if (isTopLevelFrame)
+        return true;
+    String sourceURL;
+    TextPosition sourcePosition(WTF::OrdinalNumber::beforeFirst(), WTF::OrdinalNumber());
+    auto handleViolatedDirective = [&] (const ContentSecurityPolicyDirective& violatedDirective) {
+        String consoleMessage = consoleMessageForViolation(ContentSecurityPolicyDirectiveNames::frameAncestors, violatedDirective, url, "Refused to load");
+        reportViolation(ContentSecurityPolicyDirectiveNames::frameAncestors, violatedDirective, url, consoleMessage, sourceURL, sourcePosition);
+    };
+    return allPoliciesAllow(WTFMove(handleViolatedDirective), &ContentSecurityPolicyDirectiveList::violatedDirectiveForFrameAncestorOrigins, ancestorOrigins);
+}
+
 bool ContentSecurityPolicy::allowPluginType(const String& type, const String& typeAttribute, const URL& url, bool overrideContentSecurityPolicy) const
 {
     if (overrideContentSecurityPolicy)
index 543ec09..9125080 100644 (file)
@@ -97,6 +97,7 @@ public:
     bool allowPluginType(const String& type, const String& typeAttribute, const URL&, bool overrideContentSecurityPolicy = false) const;
 
     bool allowFrameAncestors(const Frame&, const URL&, bool overrideContentSecurityPolicy = false) const;
+    WEBCORE_EXPORT bool allowFrameAncestors(const Vector<RefPtr<SecurityOrigin>>& ancestorOrigins, const URL&, bool overrideContentSecurityPolicy = false) const;
 
     enum class RedirectResponseReceived { No, Yes };
     bool allowScriptFromSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
index 5776395..6423cec 100644 (file)
@@ -70,13 +70,36 @@ static inline bool checkNonce(ContentSecurityPolicySourceListDirective* directiv
     return !directive || directive->allows(nonce);
 }
 
+// Used to compute the comparison URL when checking frame-ancestors. We do this weird conversion so that child
+// frames of a page with a unique origin (e.g. about:blank) are not blocked due to their frame-ancestors policy
+// and do not need to add the parent's URL to their policy. The latter could allow the child page to be framed
+// by anyone. See <https://github.com/w3c/webappsec/issues/311> for more details.
+static inline URL urlFromOrigin(const SecurityOrigin& origin)
+{
+    return { URL { }, origin.toString() };
+}
+
 static inline bool checkFrameAncestors(ContentSecurityPolicySourceListDirective* directive, const Frame& frame)
 {
     if (!directive)
         return true;
     bool didReceiveRedirectResponse = false;
     for (Frame* current = frame.tree().parent(); current; current = current->tree().parent()) {
-        URL origin { URL { }, current->document()->securityOrigin().toString() };
+        URL origin = urlFromOrigin(current->document()->securityOrigin());
+        if (!origin.isValid() || !directive->allows(origin, didReceiveRedirectResponse, ContentSecurityPolicySourceListDirective::ShouldAllowEmptyURLIfSourceListIsNotNone::No))
+            return false;
+    }
+    return true;
+}
+
+static inline bool checkFrameAncestors(ContentSecurityPolicySourceListDirective* directive, const Vector<RefPtr<SecurityOrigin>>& ancestorOrigins)
+{
+    if (!directive)
+        return true;
+    bool didReceiveRedirectResponse = false;
+    auto end = ancestorOrigins.end();
+    for (auto it = ancestorOrigins.begin() + 1; it != end; ++it) {
+        URL origin = urlFromOrigin(*(*it));
         if (!origin.isValid() || !directive->allows(origin, didReceiveRedirectResponse, ContentSecurityPolicySourceListDirective::ShouldAllowEmptyURLIfSourceListIsNotNone::No))
             return false;
     }
@@ -236,6 +259,13 @@ const ContentSecurityPolicyDirective* ContentSecurityPolicyDirectiveList::violat
     return m_frameAncestors.get();
 }
 
+const ContentSecurityPolicyDirective* ContentSecurityPolicyDirectiveList::violatedDirectiveForFrameAncestorOrigins(const Vector<RefPtr<SecurityOrigin>>& ancestorOrigins) const
+{
+    if (checkFrameAncestors(m_frameAncestors.get(), ancestorOrigins))
+        return nullptr;
+    return m_frameAncestors.get();
+}
+
 const ContentSecurityPolicyDirective* ContentSecurityPolicyDirectiveList::violatedDirectiveForImage(const URL& url, bool didReceiveRedirectResponse) const
 {
     ContentSecurityPolicySourceListDirective* operativeDirective = this->operativeDirective(m_imgSrc.get());
index 91261fa..2907250 100644 (file)
@@ -62,6 +62,7 @@ public:
     const ContentSecurityPolicyDirective* violatedDirectiveForFormAction(const URL&, bool didReceiveRedirectResponse) const;
     const ContentSecurityPolicyDirective* violatedDirectiveForFrame(const URL&, bool didReceiveRedirectResponse) const;
     const ContentSecurityPolicyDirective* violatedDirectiveForFrameAncestor(const Frame&) const;
+    const ContentSecurityPolicyDirective* violatedDirectiveForFrameAncestorOrigins(const Vector<RefPtr<SecurityOrigin>>&) const;
     const ContentSecurityPolicyDirective* violatedDirectiveForImage(const URL&, bool didReceiveRedirectResponse) const;
 #if ENABLE(APPLICATION_MANIFEST)
     const ContentSecurityPolicyDirective* violatedDirectiveForManifest(const URL&, bool didReceiveRedirectResponse) const;
index 4323fe6..7d4eea7 100644 (file)
@@ -43,7 +43,7 @@ enum class ContentSecurityPolicyHeaderType {
 class ContentSecurityPolicyResponseHeaders {
 public:
     ContentSecurityPolicyResponseHeaders() = default;
-    explicit ContentSecurityPolicyResponseHeaders(const ResourceResponse&);
+    WEBCORE_EXPORT explicit ContentSecurityPolicyResponseHeaders(const ResourceResponse&);
 
     ContentSecurityPolicyResponseHeaders isolatedCopy() const;
 
index 90bcd18..e14fc04 100644 (file)
@@ -84,7 +84,7 @@ String extractCharsetFromMediaType(const String&);
 void findCharsetInMediaType(const String& mediaType, unsigned int& charsetPos, unsigned int& charsetLen, unsigned int start = 0);
 XSSProtectionDisposition parseXSSProtectionHeader(const String& header, String& failureReason, unsigned& failurePosition, String& reportURL);
 AtomicString extractReasonPhraseFromHTTPStatusLine(const String&);
-XFrameOptionsDisposition parseXFrameOptionsHeader(const String&);
+WEBCORE_EXPORT XFrameOptionsDisposition parseXFrameOptionsHeader(const String&);
 
 // -1 could be set to one of the return parameters to indicate the value is not specified.
 WEBCORE_EXPORT bool parseRange(const String&, long long& rangeOffset, long long& rangeEnd, long long& rangeSuffixLength);
index faae3a8..5a9d1d8 100644 (file)
@@ -1,5 +1,49 @@
 2018-05-07  Daniel Bates  <dabates@apple.com>
 
+        Check X-Frame-Options and CSP frame-ancestors in network process
+        https://bugs.webkit.org/show_bug.cgi?id=185410
+        <rdar://problem/37733934>
+
+        Reviewed by Ryosuke Niwa.
+
+        * NetworkProcess/NetworkResourceLoadParameters.cpp:
+        (WebKit::NetworkResourceLoadParameters::encode const): Always encode the frame ancestor origins.
+        (WebKit::NetworkResourceLoadParameters::decode): Always decode the frame ancestor origins.
+        * NetworkProcess/NetworkResourceLoader.cpp:
+        (WebKit::NetworkResourceLoader::shouldInterruptLoadForXFrameOptions): Added.
+        (WebKit::NetworkResourceLoader::shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions): Added.
+        (WebKit::NetworkResourceLoader::didReceiveResponse): Check if the load needs to be interrupted due
+        to a violation of the CSP frame-ancestors directive or X-Frame-Options. If there is a violation
+        then stop the load.
+        (WebKit::NetworkResourceLoader::didRetrieveCacheEntry): Ditto.
+        (NetworkResourceLoader::addConsoleMessage): Added.
+        (NetworkResourceLoader::sendCSPViolationReport): Added.
+        * NetworkProcess/NetworkResourceLoader.h:
+        * Scripts/webkit/messages.py: Teach the generator about data types MessageLevel and MessageSource
+        as they are both defined in file JavaScriptCore/ConsoleTypes.h as opposed to independent headers.
+        Also tell the generator that these types should not be forward declared so that we can use these
+        types without their JSC:: prefix in WebPage.messages.in.
+        * WebProcess/Network/NetworkProcessConnection.cpp:
+        (WebKit::NetworkProcessConnection::didReceiveMessage): Route WebPage messages to the appropriate
+        web page.
+        * WebProcess/Network/WebLoaderStrategy.cpp:
+        (WebKit::WebLoaderStrategy::scheduleLoadFromNetworkProcess): Added message StopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied.
+        * WebProcess/Network/WebResourceLoader.cpp:
+        (WebKit::WebResourceLoader::stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied): Added.
+        * WebProcess/Network/WebResourceLoader.h:
+        * WebProcess/Network/WebResourceLoader.messages.in:
+        * WebProcess/WebPage/WebFrame.cpp:
+        (WebKit::WebFrame::addConsoleMessage):
+        * WebProcess/WebPage/WebFrame.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::addConsoleMessage): Added.
+        (WebKit::WebPage::sendCSPViolationReport): Added.
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in: Add messages AddConsoleMessage and SendCSPViolationReport
+        for adding a console message to Web Inspector and sending a CSP report, respectively.
+
+2018-05-07  Daniel Bates  <dabates@apple.com>
+
         Abstract logic to log console messages and send CSP violation reports into a client
         https://bugs.webkit.org/show_bug.cgi?id=185393
         <rdar://problem/40036053>
index 07e8e71..86b7b50 100644 (file)
@@ -98,8 +98,8 @@ void NetworkResourceLoadParameters::encode(IPC::Encoder& encoder) const
     encoder.encodeEnum(preflightPolicy);
 
     encoder << shouldEnableFromOriginResponseHeader;
-    if (shouldEnableFromOriginResponseHeader)
-        encoder << frameAncestorOrigins;
+
+    encoder << frameAncestorOrigins;
 
 #if ENABLE(CONTENT_EXTENSIONS)
     encoder << mainDocumentURL;
@@ -210,10 +210,9 @@ bool NetworkResourceLoadParameters::decode(IPC::Decoder& decoder, NetworkResourc
     if (!shouldEnableFromOriginResponseHeader)
         return false;
     result.shouldEnableFromOriginResponseHeader = *shouldEnableFromOriginResponseHeader;
-    if (result.shouldEnableFromOriginResponseHeader) {
-        if (!decoder.decode(result.frameAncestorOrigins))
-            return false;
-    }
+
+    if (!decoder.decode(result.frameAncestorOrigins))
+        return false;
     
 #if ENABLE(CONTENT_EXTENSIONS)
     if (!decoder.decode(result.mainDocumentURL))
index 1f78403..1e01920 100644 (file)
@@ -27,6 +27,7 @@
 #include "NetworkResourceLoader.h"
 
 #include "DataReference.h"
+#include "FormDataReference.h"
 #include "Logging.h"
 #include "NetworkBlobRegistry.h"
 #include "NetworkCache.h"
 #include "SessionTracker.h"
 #include "WebCoreArgumentCoders.h"
 #include "WebErrors.h"
+#include "WebPageMessages.h"
 #include "WebResourceLoaderMessages.h"
 #include "WebsiteDataStoreParameters.h"
+#include <JavaScriptCore/ConsoleTypes.h>
 #include <WebCore/BlobDataFileReference.h>
 #include <WebCore/CertificateInfo.h>
+#include <WebCore/ContentSecurityPolicy.h>
 #include <WebCore/DiagnosticLoggingKeys.h>
 #include <WebCore/HTTPHeaderNames.h>
 #include <WebCore/HTTPParsers.h>
@@ -395,6 +399,51 @@ static ResourceError fromOriginResourceError(const URL& url)
     return { errorDomainWebKitInternal, 0, url, ASCIILiteral { "Cancelled load because it violates the resource's From-Origin response header." }, ResourceError::Type::AccessControl };
 }
 
+bool NetworkResourceLoader::shouldInterruptLoadForXFrameOptions(const String& xFrameOptions, const URL& url)
+{
+    if (isMainFrameLoad())
+        return false;
+
+    switch (parseXFrameOptionsHeader(xFrameOptions)) {
+    case XFrameOptionsNone:
+    case XFrameOptionsAllowAll:
+        return false;
+    case XFrameOptionsDeny:
+        return true;
+    case XFrameOptionsSameOrigin:
+        return !SecurityOrigin::create(url)->isSameSchemeHostPort(*m_parameters.sourceOrigin);
+    case XFrameOptionsConflict: {
+        String errorMessage = "Multiple 'X-Frame-Options' headers with conflicting values ('" + xFrameOptions + "') encountered when loading '" + url.stringCenterEllipsizedToLength() + "'. Falling back to 'DENY'.";
+        send(Messages::WebPage::AddConsoleMessage { m_parameters.webFrameID,  MessageSource::JS, MessageLevel::Error, errorMessage, identifier() }, m_parameters.webPageID);
+        return true;
+    }
+    case XFrameOptionsInvalid: {
+        String errorMessage = "Invalid 'X-Frame-Options' header encountered when loading '" + url.stringCenterEllipsizedToLength() + "': '" + xFrameOptions + "' is not a recognized directive. The header will be ignored.";
+        send(Messages::WebPage::AddConsoleMessage { m_parameters.webFrameID,  MessageSource::JS, MessageLevel::Error, errorMessage, identifier() }, m_parameters.webPageID);
+        return false;
+    }
+    }
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
+bool NetworkResourceLoader::shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions(const ResourceResponse& response)
+{
+    ASSERT(isMainResource());
+    auto url = response.url();
+    ContentSecurityPolicy contentSecurityPolicy { URL { url }, this };
+    contentSecurityPolicy.didReceiveHeaders(ContentSecurityPolicyResponseHeaders { response }, originalRequest().httpReferrer());
+    if (!contentSecurityPolicy.allowFrameAncestors(m_parameters.frameAncestorOrigins, url))
+        return true;
+    String xFrameOptions = m_response.httpHeaderField(HTTPHeaderName::XFrameOptions);
+    if (!xFrameOptions.isNull() && shouldInterruptLoadForXFrameOptions(xFrameOptions, response.url())) {
+        String errorMessage = "Refused to display '" + response.url().stringCenterEllipsizedToLength() + "' in a frame because it set 'X-Frame-Options' to '" + xFrameOptions + "'.";
+        send(Messages::WebPage::AddConsoleMessage { m_parameters.webFrameID,  MessageSource::Security, MessageLevel::Error, errorMessage, identifier() }, m_parameters.webPageID);
+        return true;
+    }
+    return false;
+}
+
 auto NetworkResourceLoader::didReceiveResponse(ResourceResponse&& receivedResponse) -> ShouldContinueDidReceiveResponse
 {
     RELEASE_LOG_IF_ALLOWED("didReceiveResponse: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", httpStatusCode = %d, length = %" PRId64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, receivedResponse.httpStatusCode(), receivedResponse.expectedContentLength());
@@ -427,16 +476,17 @@ auto NetworkResourceLoader::didReceiveResponse(ResourceResponse&& receivedRespon
     ResourceError error;
     if (m_parameters.shouldEnableFromOriginResponseHeader && shouldCancelCrossOriginLoad(m_response, m_parameters.frameAncestorOrigins))
         error = fromOriginResourceError(m_response.url());
+    if (error.isNull() && isMainResource() && shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions(m_response)) {
+        send(Messages::WebResourceLoader::StopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied { });
+        return ShouldContinueDidReceiveResponse::No;
+    }
     if (error.isNull() && m_networkLoadChecker)
         error = m_networkLoadChecker->validateResponse(m_response);
     if (!error.isNull()) {
-        // FIXME: We need to make a main resource load look successful to prevent leaking its existence. See <https://bugs.webkit.org/show_bug.cgi?id=185120>.
         RunLoop::main().dispatch([protectedThis = makeRef(*this), error = WTFMove(error)] {
             if (protectedThis->m_networkLoad)
                 protectedThis->didFailLoading(error);
         });
-        // FIXME: We know that we are not going to continue this load. ShouldContinueDidReceiveResponse::No should only be returned when
-        // the network process is waiting to receive message NetworkResourceLoader::ContinueDidReceiveResponse to continue a load.
         return ShouldContinueDidReceiveResponse::No;
     }
 
@@ -726,7 +776,10 @@ void NetworkResourceLoader::didRetrieveCacheEntry(std::unique_ptr<NetworkCache::
     ResourceError error;
     if (m_parameters.shouldEnableFromOriginResponseHeader && shouldCancelCrossOriginLoad(response, m_parameters.frameAncestorOrigins))
         error = fromOriginResourceError(response.url());
-
+    if (error.isNull() && isMainResource() && shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions(response)) {
+        send(Messages::WebResourceLoader::StopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied { });
+        return;
+    }
     if (error.isNull() && m_networkLoadChecker)
         error = m_networkLoadChecker->validateResponse(response);
 
@@ -1040,4 +1093,14 @@ void NetworkResourceLoader::logCookieInformation(const String& label, const void
 }
 #endif
 
+void NetworkResourceLoader::addConsoleMessage(MessageSource messageSource, MessageLevel messageLevel, const String& message, unsigned long)
+{
+    send(Messages::WebPage::AddConsoleMessage { m_parameters.webFrameID,  messageSource, messageLevel, message, identifier() }, m_parameters.webPageID);
+}
+
+void NetworkResourceLoader::sendCSPViolationReport(URL&& reportURL, Ref<FormData>&& report)
+{
+    send(Messages::WebPage::SendCSPViolationReport { m_parameters.webFrameID, WTFMove(reportURL), IPC::FormDataReference { WTFMove(report) } }, m_parameters.webPageID);
+}
+
 } // namespace WebKit
index 57c540d..b6a585e 100644 (file)
 #include "NetworkLoadClient.h"
 #include "NetworkResourceLoadParameters.h"
 #include "ShareableResource.h"
+#include <JavaScriptCore/ConsoleTypes.h>
+#include <WebCore/ContentSecurityPolicyClient.h>
 #include <WebCore/ResourceResponse.h>
 #include <WebCore/Timer.h>
 
 namespace WebCore {
 class BlobDataFileReference;
+class FormData;
 class NetworkStorageSession;
 class ResourceRequest;
+class SecurityPolicyViolationEvent;
 }
 
 namespace WebKit {
@@ -52,7 +56,11 @@ namespace NetworkCache {
 class Entry;
 }
 
-class NetworkResourceLoader final : public RefCounted<NetworkResourceLoader>, public NetworkLoadClient, public IPC::MessageSender {
+class NetworkResourceLoader final
+    : public RefCounted<NetworkResourceLoader>
+    , public NetworkLoadClient
+    , public IPC::MessageSender
+    , public WebCore::ContentSecurityPolicyClient {
 public:
     static Ref<NetworkResourceLoader> create(NetworkResourceLoadParameters&& parameters, NetworkConnectionToWebProcess& connection, RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& reply = nullptr)
     {
@@ -105,6 +113,8 @@ public:
     void convertToDownload(DownloadID, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&);
 
     bool isMainResource() const { return m_parameters.request.requester() == WebCore::ResourceRequest::Requester::Main; }
+    bool isMainFrameLoad() const { return isMainResource() && m_parameters.frameAncestorOrigins.size() == 1; }
+
     bool isAlwaysOnLoggingAllowed() const;
 
 #if HAVE(CFNETWORK_STORAGE_PARTITIONING) && !RELEASE_LOG_DISABLED
@@ -130,6 +140,9 @@ private:
     void dispatchWillSendRequestForCacheEntry(std::unique_ptr<NetworkCache::Entry>);
     void continueProcessingCachedEntryAfterDidReceiveResponse(std::unique_ptr<NetworkCache::Entry>);
 
+    bool shouldInterruptLoadForXFrameOptions(const String&, const WebCore::URL&);
+    bool shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions(const WebCore::ResourceResponse&);
+
     enum class FirstLoad { No, Yes };
     void startNetworkLoad(WebCore::ResourceRequest&&, FirstLoad);
     void continueDidReceiveResponse();
@@ -159,6 +172,11 @@ private:
 
     WebCore::ResourceResponse sanitizeResponseIfPossible(WebCore::ResourceResponse&&, WebCore::ResourceResponse::SanitizationType);
 
+    // ContentSecurityPolicyClient
+    void addConsoleMessage(MessageSource, MessageLevel, const String&, unsigned long) final;
+    void sendCSPViolationReport(WebCore::URL&&, Ref<WebCore::FormData>&&) final;
+    void dispatchSecurityPolicyViolationEvent(Ref<WebCore::SecurityPolicyViolationEvent>&&) final { }; // No observable effect for frame-ancestors violation.
+
     const NetworkResourceLoadParameters m_parameters;
 
     Ref<NetworkConnectionToWebProcess> m_connection;
index 3ca1ff7..6ed46e9 100644 (file)
@@ -187,6 +187,8 @@ def forward_declarations_and_headers(receiver):
 
     no_forward_declaration_types = frozenset([
         'MachSendRight',
+        'MessageLevel',
+        'MessageSource',
         'String',
         'WebCore::DocumentIdentifier',
         'WebCore::ServiceWorkerIdentifier',
@@ -368,6 +370,8 @@ def headers_for_type(type):
 
     special_cases = {
         'MachSendRight': ['<wtf/MachSendRight.h>'],
+        'MessageLevel': ['<JavaScriptCore/ConsoleTypes.h>'],
+        'MessageSource': ['<JavaScriptCore/ConsoleTypes.h>'],
         'MonotonicTime': ['<wtf/MonotonicTime.h>'],
         'Seconds': ['<wtf/Seconds.h>'],
         'WallTime': ['<wtf/WallTime.h>'],
index 4b5e104..9a238ec 100644 (file)
@@ -35,6 +35,8 @@
 #include "WebCoreArgumentCoders.h"
 #include "WebLoaderStrategy.h"
 #include "WebMDNSRegisterMessages.h"
+#include "WebPage.h"
+#include "WebPageMessages.h"
 #include "WebProcess.h"
 #include "WebRTCMonitor.h"
 #include "WebRTCMonitorMessages.h"
@@ -75,6 +77,11 @@ void NetworkProcessConnection::didReceiveMessage(IPC::Connection& connection, IP
             stream->didReceiveMessage(connection, decoder);
         return;
     }
+    if (decoder.messageReceiverName() == Messages::WebPage::messageReceiverName()) {
+        if (auto* webPage = WebProcess::singleton().webPage(decoder.destinationID()))
+            webPage->didReceiveWebPageMessage(connection, decoder);
+        return;
+    }
 
 #if USE(LIBWEBRTC)
     if (decoder.messageReceiverName() == Messages::WebRTCSocket::messageReceiverName()) {
index b691fee..6c32406 100644 (file)
@@ -327,16 +327,11 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL
     loadParameters.isMainFrameNavigation = resourceLoader.frame() && resourceLoader.frame()->isMainFrame() && resourceLoader.options().mode == FetchOptions::Mode::Navigate;
 
     loadParameters.shouldEnableFromOriginResponseHeader = RuntimeEnabledFeatures::sharedFeatures().fromOriginResponseHeaderEnabled() && !loadParameters.isMainFrameNavigation;
-    if (loadParameters.shouldEnableFromOriginResponseHeader) {
-        Vector<RefPtr<WebCore::SecurityOrigin>> frameAncestorOrigins;
-        for (auto* frame = resourceLoader.frame(); frame; frame = frame->tree().parent()) {
-            if (frame->document())
-                frameAncestorOrigins.append(makeRefPtr(frame->document()->securityOrigin()));
-            if (frame->isMainFrame())
-                break;
-        }
-        loadParameters.frameAncestorOrigins = WTFMove(frameAncestorOrigins);
-    }
+
+    Vector<RefPtr<SecurityOrigin>> frameAncestorOrigins;
+    for (auto* frame = resourceLoader.frame(); frame; frame = frame->tree().parent())
+        frameAncestorOrigins.append(makeRefPtr(frame->document()->securityOrigin()));
+    loadParameters.frameAncestorOrigins = WTFMove(frameAncestorOrigins);
 
     ASSERT((loadParameters.webPageID && loadParameters.webFrameID) || loadParameters.clientCredentialPolicy == ClientCredentialPolicy::CannotAskClientForCredentials);
 
index ca46482..c974ff8 100644 (file)
@@ -180,6 +180,14 @@ void WebResourceLoader::didBlockAuthenticationChallenge()
     m_coreLoader->didBlockAuthenticationChallenge();
 }
 
+void WebResourceLoader::stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied()
+{
+    LOG(Network, "(WebProcess) WebResourceLoader::stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied for '%s'", m_coreLoader->url().string().latin1().data());
+    RELEASE_LOG_IF_ALLOWED("stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_trackingParameters.pageID, m_trackingParameters.frameID, m_trackingParameters.resourceID);
+
+    m_coreLoader->documentLoader()->stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied(m_coreLoader->identifier(), ResourceResponse { });
+}
+
 #if ENABLE(SHAREABLE_RESOURCE)
 void WebResourceLoader::didReceiveResource(const ShareableResource::Handle& handle)
 {
index d2ae6a2..e7bed02 100644 (file)
@@ -82,6 +82,9 @@ private:
     void didFinishResourceLoad(const WebCore::NetworkLoadMetrics&);
     void didFailResourceLoad(const WebCore::ResourceError&);
     void didBlockAuthenticationChallenge();
+
+    void stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied();
+
 #if ENABLE(SHAREABLE_RESOURCE)
     void didReceiveResource(const ShareableResource::Handle&);
 #endif
index 95f69cb..4658458 100644 (file)
@@ -30,6 +30,8 @@ messages -> WebResourceLoader LegacyReceiver {
     DidFailResourceLoad(WebCore::ResourceError error)
     DidBlockAuthenticationChallenge()
 
+    StopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied()
+
 #if ENABLE(SHAREABLE_RESOURCE)
     // DidReceiveResource is for when we have the entire resource data available at once, such as when the resource is cached in memory
     DidReceiveResource(WebKit::ShareableResource::Handle resource)
index 16abe55..43c1ae0 100644 (file)
@@ -315,6 +315,14 @@ void WebFrame::convertMainResourceLoadToDownload(DocumentLoader* documentLoader,
     webProcess.ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::ConvertMainResourceLoadToDownload(sessionID, mainResourceLoadIdentifier, policyDownloadID, request, response), 0);
 }
 
+void WebFrame::addConsoleMessage(MessageSource messageSource, MessageLevel messageLevel, const String& message, uint64_t requestID)
+{
+    if (!m_coreFrame)
+        return;
+    if (auto* document = m_coreFrame->document())
+        document->addConsoleMessage(messageSource, messageLevel, message, requestID);
+}
+
 String WebFrame::source() const
 {
     if (!m_coreFrame)
index 9fef7f1..a73d22d 100644 (file)
@@ -30,6 +30,7 @@
 #include "ShareableBitmap.h"
 #include "WKBase.h"
 #include "WebFrameLoaderClient.h"
+#include <JavaScriptCore/ConsoleTypes.h>
 #include <JavaScriptCore/JSBase.h>
 #include <WebCore/FrameLoaderClient.h>
 #include <WebCore/FrameLoaderTypes.h>
@@ -94,6 +95,8 @@ public:
     void startDownload(const WebCore::ResourceRequest&, const String& suggestedName = { });
     void convertMainResourceLoadToDownload(WebCore::DocumentLoader*, PAL::SessionID, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&);
 
+    void addConsoleMessage(MessageSource, MessageLevel, const String&, uint64_t requestID = 0);
+
     String source() const;
     String contentsAsString() const;
     String selectionAsString() const;
index e204375..fdd2056 100644 (file)
@@ -38,6 +38,7 @@
 #include "EditorState.h"
 #include "EventDispatcher.h"
 #include "FindController.h"
+#include "FormDataReference.h"
 #include "GeolocationPermissionRequestManager.h"
 #include "InjectedBundle.h"
 #include "InjectedBundleBackForwardList.h"
 #include <WebCore/NotImplemented.h>
 #include <WebCore/Page.h>
 #include <WebCore/PageConfiguration.h>
+#include <WebCore/PingLoader.h>
 #include <WebCore/PlatformKeyboardEvent.h>
 #include <WebCore/PluginDocument.h>
 #include <WebCore/PrintContext.h>
@@ -469,6 +471,8 @@ WebPage::WebPage(uint64_t pageID, WebPageCreationParameters&& parameters)
     WebCore::provideUserMediaTo(m_page.get(), new WebUserMediaClient(*this));
 #endif
 
+    m_page->settings().setNetworkProcessCSPFrameAncestorsCheckingEnabled(true);
+
     m_page->setControlledByAutomation(parameters.controlledByAutomation);
 
 #if ENABLE(REMOTE_INSPECTOR)
@@ -3302,6 +3306,21 @@ WebFullScreenManager* WebPage::fullScreenManager()
 }
 #endif
 
+void WebPage::addConsoleMessage(uint64_t frameID, MessageSource messageSource, MessageLevel messageLevel, const String& message, uint64_t requestID)
+{
+    if (auto* frame = WebProcess::singleton().webFrame(frameID))
+        frame->addConsoleMessage(messageSource, messageLevel, message, requestID);
+}
+
+void WebPage::sendCSPViolationReport(uint64_t frameID, const WebCore::URL& reportURL, IPC::FormDataReference&& reportData)
+{
+    auto report = reportData.takeData();
+    if (!report)
+        return;
+    if (auto* frame = WebProcess::singleton().webFrame(frameID))
+        PingLoader::sendViolationReport(*frame->coreFrame(), reportURL, report.releaseNonNull(), ViolationReportType::ContentSecurityPolicy);
+}
+
 NotificationPermissionRequestManager* WebPage::notificationPermissionRequestManager()
 {
     if (m_notificationPermissionRequestManager)
index 07c4124..33f1bec 100644 (file)
@@ -119,8 +119,9 @@ class Array;
 }
 
 namespace IPC {
-class Decoder;
 class Connection;
+class Decoder;
+class FormDataReference;
 }
 
 namespace WebCore {
@@ -306,6 +307,9 @@ public:
     WebFullScreenManager* fullScreenManager();
 #endif
 
+    void addConsoleMessage(uint64_t frameID, MessageSource, MessageLevel, const String&, uint64_t requestID = 0);
+    void sendCSPViolationReport(uint64_t frameID, const WebCore::URL& reportURL, IPC::FormDataReference&&);
+
     // -- Called by the DrawingArea.
     // FIXME: We could genericize these into a DrawingArea client interface. Would that be beneficial?
     void drawRect(WebCore::GraphicsContext&, const WebCore::IntRect&);
@@ -1079,6 +1083,8 @@ public:
 
     bool isSuspended() const { return m_isSuspended; }
 
+    void didReceiveWebPageMessage(IPC::Connection&, IPC::Decoder&);
+
 private:
     WebPage(uint64_t pageID, WebPageCreationParameters&&);
 
@@ -1101,7 +1107,6 @@ private:
     void sendTouchBarMenuItemDataRemovedUpdate(WebCore::HTMLMenuItemElement&);
 #endif
 
-    void didReceiveWebPageMessage(IPC::Connection&, IPC::Decoder&);
     void didReceiveSyncWebPageMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&);
 
 #if PLATFORM(IOS)
index 5d1cf6f..82b2028 100644 (file)
@@ -27,6 +27,9 @@ messages -> WebPage LegacyReceiver {
 
     SetDrawsBackground(bool drawsBackground)
 
+    AddConsoleMessage(uint64_t frameID, enum MessageSource messageSource, enum MessageLevel messageLevel, String message, uint64_t requestID)
+    SendCSPViolationReport(uint64_t frameID, WebCore::URL reportURL, IPC::FormDataReference reportData)
+
 #if PLATFORM(COCOA)
     SetTopContentInsetFenced(float contentInset, IPC::Attachment fencePort)
 #endif