Prevent non app-bound domain cookies from being read or set using API calls
authorkatherine_cheney@apple.com <katherine_cheney@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 3 Apr 2020 23:39:06 +0000 (23:39 +0000)
committerkatherine_cheney@apple.com <katherine_cheney@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 3 Apr 2020 23:39:06 +0000 (23:39 +0000)
https://bugs.webkit.org/show_bug.cgi?id=209926
<rdar://problem/61071428>

Reviewed by Brady Eidson.

Source/WebKit:

This patch filters out setting and fetching of cookies via API call
to only set or return app-bound cookies.

* UIProcess/API/APIHTTPCookieStore.cpp:
(API::HTTPCookieStore::filterAppBoundCookies):
This function queries the websiteDataStore for the WKAppBoundDomains
entries and filters out non app-bound domains.

(API::HTTPCookieStore::cookies):
(API::HTTPCookieStore::cookiesForURL):
(API::HTTPCookieStore::setCookies):
These functions were updated to set/return the cookies after they've
been filtered through the WKAppBoundDomains.

* UIProcess/API/APIHTTPCookieStore.h:
* UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
(-[WKWebsiteDataStore _appBoundDomains:]):
* UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm:
(WebKit::WebsiteDataStore::getAppBoundDomains const):
(WebKit::WebsiteDataStore::appBoundDomainsForTesting const): Deleted.
Utilize a function formerly used for testing only to be used in the
HTTPCookieStore.

* UIProcess/WebsiteData/WebsiteDataStore.h:

Tools:

Added 3 new API tests to test that non app-bound cookies are not being
set or returned via API calls. Also added a function to reset state
between tests for internal debugging.

* TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm:
(setUpCookieTest):
(TEST):

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

Source/WebKit/ChangeLog
Source/WebKit/UIProcess/API/APIHTTPCookieStore.cpp
Source/WebKit/UIProcess/API/APIHTTPCookieStore.h
Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm
Source/WebKit/UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm
Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm

index 16714b6..9da2035 100644 (file)
@@ -1,3 +1,36 @@
+2020-04-03  Kate Cheney  <katherine_cheney@apple.com>
+
+        Prevent non app-bound domain cookies from being read or set using API calls
+        https://bugs.webkit.org/show_bug.cgi?id=209926
+        <rdar://problem/61071428>
+
+        Reviewed by Brady Eidson.
+
+        This patch filters out setting and fetching of cookies via API call 
+        to only set or return app-bound cookies.
+
+        * UIProcess/API/APIHTTPCookieStore.cpp:
+        (API::HTTPCookieStore::filterAppBoundCookies):
+        This function queries the websiteDataStore for the WKAppBoundDomains
+        entries and filters out non app-bound domains.
+
+        (API::HTTPCookieStore::cookies):
+        (API::HTTPCookieStore::cookiesForURL):
+        (API::HTTPCookieStore::setCookies):
+        These functions were updated to set/return the cookies after they've
+        been filtered through the WKAppBoundDomains.
+
+        * UIProcess/API/APIHTTPCookieStore.h:
+        * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
+        (-[WKWebsiteDataStore _appBoundDomains:]):
+        * UIProcess/WebsiteData/Cocoa/WebsiteDataStoreCocoa.mm:
+        (WebKit::WebsiteDataStore::getAppBoundDomains const):
+        (WebKit::WebsiteDataStore::appBoundDomainsForTesting const): Deleted.
+        Utilize a function formerly used for testing only to be used in the
+        HTTPCookieStore.
+
+        * UIProcess/WebsiteData/WebsiteDataStore.h:
+
 2020-04-03  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Add more logging to help diagnose <webkit.org/b/209685>
index b416be3..97e93cb 100644 (file)
 #include "WebCookieManagerProxy.h"
 #include "WebProcessPool.h"
 #include "WebsiteDataStore.h"
+#include "WebsiteDataStoreParameters.h"
 #include <WebCore/Cookie.h>
 #include <WebCore/CookieStorage.h>
 #include <WebCore/HTTPCookieAcceptPolicy.h>
 #include <WebCore/NetworkStorageSession.h>
 
+#if USE(APPLE_INTERNAL_SDK)
+#include <WebKitAdditions/HTTPCookieStoreAdditions.h>
+#else
+#define IN_APP_BROWSER_PRIVACY_ENABLED false
+#define IMPLEMENT_IN_APP_BROWSER_PRIVACY_ENABLED
+#endif
+
 using namespace WebKit;
 
 namespace API {
@@ -54,6 +62,27 @@ HTTPCookieStore::~HTTPCookieStore()
     unregisterForNewProcessPoolNotifications();
 }
 
+void HTTPCookieStore::filterAppBoundCookies(const Vector<WebCore::Cookie>& cookies, CompletionHandler<void(Vector<WebCore::Cookie>&&)>&& completionHandler)
+{
+    Vector<WebCore::Cookie> appBoundCookies;
+#if PLATFORM(IOS_FAMILY)
+    m_owningDataStore->getAppBoundDomains([this, protectedThis = makeRef(*this), cookies, appBoundCookies = WTFMove(appBoundCookies), completionHandler = WTFMove(completionHandler)] (auto& domains) mutable {
+        if (m_owningDataStore->parameters().networkSessionParameters.isInAppBrowserPrivacyEnabled || IN_APP_BROWSER_PRIVACY_ENABLED) {
+            IMPLEMENT_IN_APP_BROWSER_PRIVACY_ENABLED
+            for (auto& cookie : cookies) {
+                if (domains.contains(WebCore::RegistrableDomain::uncheckedCreateFromHost(cookie.domain)))
+                    appBoundCookies.append(cookie);
+            }
+        } else
+            appBoundCookies = cookies;
+        completionHandler(WTFMove(appBoundCookies));
+    });
+#else
+    appBoundCookies = cookies;
+    completionHandler(WTFMove(appBoundCookies));
+#endif
+}
+
 void HTTPCookieStore::cookies(CompletionHandler<void(const Vector<WebCore::Cookie>&)>&& completionHandler)
 {
     auto* pool = m_owningDataStore->processPoolForCookieStorageOperations();
@@ -63,15 +92,15 @@ void HTTPCookieStore::cookies(CompletionHandler<void(const Vector<WebCore::Cooki
             allCookies = getAllDefaultUIProcessCookieStoreCookies();
         allCookies.appendVector(m_owningDataStore->pendingCookies());
 
-        RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), allCookies] () mutable {
-            completionHandler(allCookies);
+        RunLoop::main().dispatch([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler), allCookies] () mutable {
+            filterAppBoundCookies(allCookies, WTFMove(completionHandler));
         });
         return;
     }
 
     auto* cookieManager = pool->supplement<WebKit::WebCookieManagerProxy>();
-    cookieManager->getAllCookies(m_owningDataStore->sessionID(), [pool = WTFMove(pool), completionHandler = WTFMove(completionHandler)] (const Vector<WebCore::Cookie>& cookies) mutable {
-        completionHandler(cookies);
+    cookieManager->getAllCookies(m_owningDataStore->sessionID(), [this, protectedThis = makeRef(*this), pool = WTFMove(pool), completionHandler = WTFMove(completionHandler)] (const Vector<WebCore::Cookie>& cookies) mutable {
+        filterAppBoundCookies(cookies, WTFMove(completionHandler));
     });
 }
 
@@ -82,30 +111,32 @@ void HTTPCookieStore::cookiesForURL(WTF::URL&& url, CompletionHandler<void(Vecto
         return completionHandler({ });
 
     auto* cookieManager = pool->supplement<WebKit::WebCookieManagerProxy>();
-    cookieManager->getCookies(m_owningDataStore->sessionID(), url, [completionHandler = WTFMove(completionHandler)] (Vector<WebCore::Cookie>&& cookies) mutable {
-        completionHandler(WTFMove(cookies));
+    cookieManager->getCookies(m_owningDataStore->sessionID(), url, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] (Vector<WebCore::Cookie>&& cookies) mutable {
+        filterAppBoundCookies(cookies, WTFMove(completionHandler));
     });
 }
 
 void HTTPCookieStore::setCookies(const Vector<WebCore::Cookie>& cookies, CompletionHandler<void()>&& completionHandler)
 {
-    auto* pool = m_owningDataStore->processPoolForCookieStorageOperations();
-    if (!pool) {
-        for (auto& cookie : cookies) {
-            // FIXME: pendingCookies used for defaultSession because session cookies cannot be propagated to Network Process with uiProcessCookieStorageIdentifier.
-            if (m_owningDataStore->sessionID() == PAL::SessionID::defaultSessionID() && !cookie.session)
-                setCookieInDefaultUIProcessCookieStore(cookie);
-            else
-                m_owningDataStore->addPendingCookie(cookie);
+    filterAppBoundCookies(cookies, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] (auto&& appBoundCookies) mutable {
+        auto* pool = m_owningDataStore->processPoolForCookieStorageOperations();
+        if (!pool) {
+            for (auto& cookie : appBoundCookies) {
+                // FIXME: pendingCookies used for defaultSession because session cookies cannot be propagated to Network Process with uiProcessCookieStorageIdentifier.
+                if (m_owningDataStore->sessionID() == PAL::SessionID::defaultSessionID() && !cookie.session)
+                    setCookieInDefaultUIProcessCookieStore(cookie);
+                else
+                    m_owningDataStore->addPendingCookie(cookie);
+            }
+
+            RunLoop::main().dispatch(WTFMove(completionHandler));
+            return;
         }
 
-        RunLoop::main().dispatch(WTFMove(completionHandler));
-        return;
-    }
-
-    auto* cookieManager = pool->supplement<WebKit::WebCookieManagerProxy>();
-    cookieManager->setCookies(m_owningDataStore->sessionID(), cookies, [pool = WTFMove(pool), completionHandler = WTFMove(completionHandler)] () mutable {
-        completionHandler();
+        auto* cookieManager = pool->supplement<WebKit::WebCookieManagerProxy>();
+        cookieManager->setCookies(m_owningDataStore->sessionID(), appBoundCookies, [pool = WTFMove(pool), completionHandler = WTFMove(completionHandler)] () mutable {
+            completionHandler();
+        });
     });
 }
 
index 4db75b3..61dff2c 100644 (file)
@@ -77,6 +77,8 @@ public:
     void cookiesDidChange();
     void cookieManagerDestroyed();
 
+    void filterAppBoundCookies(const Vector<WebCore::Cookie>&, CompletionHandler<void(Vector<WebCore::Cookie>&&)>&&);
+
 private:
     HTTPCookieStore(WebKit::WebsiteDataStore&);
 
index 6e578e0..a48e1b6 100644 (file)
@@ -613,7 +613,7 @@ static Vector<WebKit::WebsiteDataRecord> toWebsiteDataRecords(NSArray *dataRecor
 
 - (void)_appBoundDomains:(void (^)(NSArray<NSString *> *))completionHandler
 {
-    _websiteDataStore->appBoundDomainsForTesting([completionHandler = makeBlockPtr(completionHandler)](auto& domains) mutable {
+    _websiteDataStore->getAppBoundDomains([completionHandler = makeBlockPtr(completionHandler)](auto& domains) mutable {
         Vector<RefPtr<API::Object>> apiDomains;
         apiDomains.reserveInitialCapacity(domains.size());
         for (auto& domain : domains)
index a70b7d5..22c98ef 100644 (file)
@@ -466,8 +466,10 @@ void WebsiteDataStore::beginAppBoundDomainCheck(const URL& requestURL, WebFrameP
     });
 }
 
-void WebsiteDataStore::appBoundDomainsForTesting(CompletionHandler<void(const HashSet<WebCore::RegistrableDomain>&)>&& completionHandler) const
+void WebsiteDataStore::getAppBoundDomains(CompletionHandler<void(const HashSet<WebCore::RegistrableDomain>&)>&& completionHandler) const
 {
+    ASSERT(RunLoop::isMain());
+
     ensureAppBoundDomains([completionHandler = WTFMove(completionHandler)] (auto& domains) mutable {
         completionHandler(domains);
     });
index 555d356..e842313 100644 (file)
@@ -287,7 +287,7 @@ public:
     void setInAppBrowserPrivacyEnabled(bool enabled, CompletionHandler<void()>&&);
 
     void beginAppBoundDomainCheck(const URL&, WebFramePolicyListenerProxy&);
-    void appBoundDomainsForTesting(CompletionHandler<void(const HashSet<WebCore::RegistrableDomain>&)>&&) const;
+    void getAppBoundDomains(CompletionHandler<void(const HashSet<WebCore::RegistrableDomain>&)>&&) const;
     void ensureAppBoundDomains(CompletionHandler<void(const HashSet<WebCore::RegistrableDomain>&)>&&) const;
     void reinitializeAppBoundDomains();
 
index 5eaf829..252b4cf 100644 (file)
@@ -1,3 +1,19 @@
+2020-04-03  Kate Cheney  <katherine_cheney@apple.com>
+
+        Prevent non app-bound domain cookies from being read or set using API calls
+        https://bugs.webkit.org/show_bug.cgi?id=209926
+        <rdar://problem/61071428>
+
+        Reviewed by Brady Eidson.
+
+        Added 3 new API tests to test that non app-bound cookies are not being
+        set or returned via API calls. Also added a function to reset state
+        between tests for internal debugging.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm:
+        (setUpCookieTest):
+        (TEST):
+
 2020-04-03  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Add more logging to help diagnose <webkit.org/b/209685>
index ea70eff..37f8a11 100644 (file)
@@ -31,6 +31,7 @@
 #import "WKWebViewConfigurationExtras.h"
 #import <WebCore/RegistrableDomain.h>
 #import <WebCore/RuntimeApplicationChecks.h>
+#import <WebKit/WKHTTPCookieStorePrivate.h>
 #import <WebKit/WKPreferencesPrivate.h>
 #import <WebKit/WKUserContentControllerPrivate.h>
 #import <WebKit/WKWebsiteDataStorePrivate.h>
@@ -78,6 +79,11 @@ static NSString * const userScriptSource = @"window.wkUserScriptInjected = true"
 
 @end
 
+static void cleanUpInAppBrowserPrivacyTestSettings()
+{
+    IN_APP_BROWSER_PRIVACY_ADDITIONS_2
+}
+
 static void initializeInAppBrowserPrivacyTestSettings()
 {
     RunLoop::initializeMainRunLoop();
@@ -119,6 +125,7 @@ TEST(InAppBrowserPrivacy, NonAppBoundDomainFailedUserScriptAtStart)
     [webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
         EXPECT_EQ(NO, [result boolValue]);
         EXPECT_FALSE(!!error);
+        cleanUpInAppBrowserPrivacyTestSettings();
         isDone = true;
     }];
 
@@ -160,6 +167,7 @@ TEST(InAppBrowserPrivacy, NonAppBoundDomainFailedUserScriptAtEnd)
     [webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
         EXPECT_EQ(NO, [result boolValue]);
         EXPECT_FALSE(!!error);
+        cleanUpInAppBrowserPrivacyTestSettings();
         isDone = true;
     }];
 
@@ -202,6 +210,7 @@ TEST(InAppBrowserPrivacy, NonAppBoundDomainFailedUserAgentScripts)
     [webView2 evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
         EXPECT_FALSE(result);
         EXPECT_TRUE(!!error);
+        cleanUpInAppBrowserPrivacyTestSettings();
         isDone = true;
     }];
 
@@ -245,6 +254,7 @@ TEST(InAppBrowserPrivacy, SwapBackToAppBoundRejectsUserScript)
     [webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
         EXPECT_FALSE(result);
         EXPECT_TRUE(!!error);
+        cleanUpInAppBrowserPrivacyTestSettings();
         isDone = true;
     }];
 
@@ -265,6 +275,7 @@ TEST(InAppBrowserPrivacy, AppBoundDomains)
         for (int i = 0; i < length; i++)
             EXPECT_WK_STREQ([sortedDomains objectAtIndex:i], [domainsToCompare objectAtIndex:i]);
 
+        cleanUpInAppBrowserPrivacyTestSettings();
         isDone = true;
     }];
     TestWebKitAPI::Util::run(&isDone);
@@ -284,6 +295,7 @@ TEST(InAppBrowserPrivacy, LocalFilesAreAppBound)
     isDone = false;
     [webView _isNavigatingToAppBoundDomain:^(BOOL isAppBound) {
         EXPECT_TRUE(isAppBound);
+        cleanUpInAppBrowserPrivacyTestSettings();
         isDone = true;
     }];
     TestWebKitAPI::Util::run(&isDone);
@@ -302,6 +314,7 @@ TEST(InAppBrowserPrivacy, DataFilesAreAppBound)
     isDone = false;
     [webView _isNavigatingToAppBoundDomain:^(BOOL isAppBound) {
         EXPECT_TRUE(isAppBound);
+        cleanUpInAppBrowserPrivacyTestSettings();
         isDone = true;
     }];
     TestWebKitAPI::Util::run(&isDone);
@@ -320,6 +333,7 @@ TEST(InAppBrowserPrivacy, AboutFilesAreAppBound)
     isDone = false;
     [webView _isNavigatingToAppBoundDomain:^(BOOL isAppBound) {
         EXPECT_TRUE(isAppBound);
+        cleanUpInAppBrowserPrivacyTestSettings();
         isDone = true;
     }];
     TestWebKitAPI::Util::run(&isDone);
@@ -364,6 +378,7 @@ TEST(InAppBrowserPrivacy, NonAppBoundUserStyleSheetForSpecificWebViewFails)
     [[configuration userContentController] _addUserStyleSheet:styleSheet.get()];
 
     expectScriptEvaluatesToColor(webView.get(), backgroundColorScript, redInRGB);
+    cleanUpInAppBrowserPrivacyTestSettings();
 }
 
 TEST(InAppBrowserPrivacy, NonAppBoundUserStyleSheetForAllWebViewsFails)
@@ -385,6 +400,7 @@ TEST(InAppBrowserPrivacy, NonAppBoundUserStyleSheetForAllWebViewsFails)
     [[configuration userContentController] _addUserStyleSheet:styleSheet.get()];
 
     expectScriptEvaluatesToColor(webView.get(), backgroundColorScript, redInRGB);
+    cleanUpInAppBrowserPrivacyTestSettings();
 }
 
 TEST(InAppBrowserPrivacy, NonAppBoundUserStyleSheetAffectingAllFramesFails)
@@ -410,6 +426,7 @@ TEST(InAppBrowserPrivacy, NonAppBoundUserStyleSheetAffectingAllFramesFails)
 
     // The subframe should also be affected.
     expectScriptEvaluatesToColor(webView.get(), frameBackgroundColorScript, redInRGB);
+    cleanUpInAppBrowserPrivacyTestSettings();
 }
 
 TEST(InAppBrowserPrivacy, NonAppBoundDomainCannotAccessMessageHandlers)
@@ -436,6 +453,7 @@ TEST(InAppBrowserPrivacy, NonAppBoundDomainCannotAccessMessageHandlers)
     // Set the background color to red if message handlers returned null so we can
     // check without needing a message handler.
     expectScriptEvaluatesToColor(webView.get(), backgroundColorScript, redInRGB);
+    cleanUpInAppBrowserPrivacyTestSettings();
 }
 
 TEST(InAppBrowserPrivacy, AppBoundToNonAppBoundDomainCannotAccessMessageHandlers)
@@ -474,6 +492,254 @@ TEST(InAppBrowserPrivacy, AppBoundToNonAppBoundDomainCannotAccessMessageHandlers
     // Set the background color to red if message handlers returned null so we can
     // check without needing a message handler.
     expectScriptEvaluatesToColor(webView.get(), backgroundColorScript, redInRGB);
+    cleanUpInAppBrowserPrivacyTestSettings();
+}
+
+static RetainPtr<WKHTTPCookieStore> globalCookieStore;
+static bool gotFlag = false;
+
+static void setUpCookieTest()
+{
+    globalCookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore];
+    NSArray<NSHTTPCookie *> *cookies = nil;
+    [globalCookieStore getAllCookies:[cookiesPtr = &cookies](NSArray<NSHTTPCookie *> *nsCookies) {
+        *cookiesPtr = [nsCookies retain];
+        gotFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&gotFlag);
+
+    for (id cookie in cookies) {
+        gotFlag = false;
+        [globalCookieStore deleteCookie:cookie completionHandler:[]() {
+            gotFlag = true;
+        }];
+        TestWebKitAPI::Util::run(&gotFlag);
+    }
+
+    cookies = nil;
+    gotFlag = false;
+    [globalCookieStore getAllCookies:[cookiesPtr = &cookies](NSArray<NSHTTPCookie *> *nsCookies) {
+        *cookiesPtr = [nsCookies retain];
+        gotFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&gotFlag);
+
+    // Make sure the cookie store starts out empty.
+    ASSERT_EQ(cookies.count, 0u);
+    [cookies release];
+
+    gotFlag = false;
+}
+
+TEST(InAppBrowserPrivacy, SetCookieForNonAppBoundDomainFails)
+{
+    initializeInAppBrowserPrivacyTestSettings();
+    [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+
+    auto dataStore = [WKWebsiteDataStore defaultDataStore];
+    auto webView = adoptNS([TestWKWebView new]);
+    [webView loadHTMLString:@"Oh hello" baseURL:[NSURL URLWithString:@"http://webkit.org"]];
+    [webView _test_waitForDidFinishNavigation];
+
+    setUpCookieTest();
+    globalCookieStore = [dataStore httpCookieStore];
+
+    NSArray<NSHTTPCookie *> *cookies = nil;
+
+    // Non app-bound cookie.
+    RetainPtr<NSHTTPCookie> nonAppBoundCookie = [NSHTTPCookie cookieWithProperties:@{
+        NSHTTPCookiePath: @"/",
+        NSHTTPCookieName: @"nonAppBoundName",
+        NSHTTPCookieValue: @"nonAppBoundValue",
+        NSHTTPCookieDomain: @"nonAppBoundDomain.com",
+    }];
+
+    // App-bound cookie.
+    RetainPtr<NSHTTPCookie> appBoundCookie = [NSHTTPCookie cookieWithProperties:@{
+        NSHTTPCookiePath: @"/",
+        NSHTTPCookieName: @"webKitName",
+        NSHTTPCookieValue: @"webKitValue",
+        NSHTTPCookieDomain: @"www.webkit.org",
+    }];
+
+    gotFlag = false;
+    // This should not actually set a cookie.
+    [globalCookieStore setCookie:nonAppBoundCookie.get() completionHandler:[]() {
+        gotFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&gotFlag);
+    gotFlag = false;
+
+    // This should successfully set a cookie.
+    [globalCookieStore setCookie:appBoundCookie.get() completionHandler:[]() {
+        gotFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&gotFlag);
+
+    cleanUpInAppBrowserPrivacyTestSettings();
+    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+    gotFlag = false;
+
+    // Check the cookie store to make sure only one cookie was set.
+    [globalCookieStore getAllCookies:[cookiesPtr = &cookies](NSArray<NSHTTPCookie *> *nsCookies) {
+        *cookiesPtr = [nsCookies retain];
+        gotFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&gotFlag);
+
+    ASSERT_EQ(cookies.count, 1u);
+
+    [cookies release];
+    gotFlag = false;
+    [globalCookieStore deleteCookie:appBoundCookie.get() completionHandler:[]() {
+        gotFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&gotFlag);
+}
+
+TEST(InAppBrowserPrivacy, GetCookieForNonAppBoundDomainFails)
+{
+    // Since we can't set non-app-bound cookies with In-App Browser privacy protections on,
+    // we can turn the protections off to set a cookie we will then try to get with protections enabled.
+    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+
+    setUpCookieTest();
+    globalCookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore];
+    NSArray<NSHTTPCookie *> *cookies = nil;
+
+    // Non app-bound cookie.
+    RetainPtr<NSHTTPCookie> nonAppBoundCookie = [NSHTTPCookie cookieWithProperties:@{
+        NSHTTPCookiePath: @"/",
+        NSHTTPCookieName: @"CookieName",
+        NSHTTPCookieValue: @"CookieValue",
+        NSHTTPCookieDomain: @"nonAppBoundDomain.com",
+    }];
+
+    // App-bound cookie.
+    RetainPtr<NSHTTPCookie> appBoundCookie = [NSHTTPCookie cookieWithProperties:@{
+        NSHTTPCookiePath: @"/",
+        NSHTTPCookieName: @"OtherCookieName",
+        NSHTTPCookieValue: @"OtherCookieValue",
+        NSHTTPCookieDomain: @"www.webkit.org",
+    }];
+
+    auto webView = adoptNS([TestWKWebView new]);
+    [webView synchronouslyLoadHTMLString:@"start network process"];
+
+    // This should successfully set a cookie because protections are off.
+    [globalCookieStore setCookie:nonAppBoundCookie.get() completionHandler:[]() {
+        gotFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&gotFlag);
+    gotFlag = false;
+
+    [globalCookieStore setCookie:appBoundCookie.get() completionHandler:[]() {
+        gotFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&gotFlag);
+
+    gotFlag = false;
+    [globalCookieStore getAllCookies:[cookiesPtr = &cookies](NSArray<NSHTTPCookie *> *nsCookies) {
+        *cookiesPtr = [nsCookies retain];
+        gotFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&gotFlag);
+
+    // Confirm both cookies are in the store.
+    ASSERT_EQ(cookies.count, 2u);
+
+    // Now enable protections and ensure we can only retrieve the app-bound cookies.
+    [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+    initializeInAppBrowserPrivacyTestSettings();
+
+    gotFlag = false;
+    [globalCookieStore getAllCookies:[cookiesPtr = &cookies](NSArray<NSHTTPCookie *> *nsCookies) {
+        *cookiesPtr = [nsCookies retain];
+        gotFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&gotFlag);
+
+    ASSERT_EQ(cookies.count, 1u);
+
+    [cookies release];
+
+    gotFlag = false;
+    [globalCookieStore deleteCookie:nonAppBoundCookie.get() completionHandler:[]() {
+        gotFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&gotFlag);
+
+    gotFlag = false;
+    [globalCookieStore deleteCookie:appBoundCookie.get() completionHandler:[]() {
+        // Reset flag.
+        [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+        cleanUpInAppBrowserPrivacyTestSettings();
+        gotFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&gotFlag);
+}
+
+TEST(InAppBrowserPrivacy, GetCookieForURLFails)
+{
+    // Since we can't set non-app-bound cookies with In-App Browser privacy protections on,
+    // we can turn the protections off to set a cookie we will then try to get with protections enabled.
+    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+    setUpCookieTest();
+
+    globalCookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore];
+    NSHTTPCookie *nonAppBoundCookie = [NSHTTPCookie cookieWithProperties:@{
+        NSHTTPCookiePath: @"/",
+        NSHTTPCookieName: @"nonAppBoundName",
+        NSHTTPCookieValue: @"nonAppBoundValue",
+        NSHTTPCookieDomain: @"nonAppBoundDomain.com",
+    }];
+    
+    NSHTTPCookie *appBoundCookie = [NSHTTPCookie cookieWithProperties:@{
+        NSHTTPCookiePath: @"/",
+        NSHTTPCookieName: @"webKitName",
+        NSHTTPCookieValue: @"webKitValue",
+        NSHTTPCookieDomain: @"webkit.org",
+    }];
+
+    __block bool done = false;
+    auto webView = adoptNS([TestWKWebView new]);
+    [webView synchronouslyLoadHTMLString:@"start network process"];
+    [globalCookieStore setCookie:nonAppBoundCookie completionHandler:^{
+        [globalCookieStore setCookie:appBoundCookie completionHandler:^{
+
+            // Now enable protections and ensure we can only retrieve the app-bound cookies.
+            [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+            initializeInAppBrowserPrivacyTestSettings();
+
+            [globalCookieStore _getCookiesForURL:[NSURL URLWithString:@"https://webkit.org/"] completionHandler:^(NSArray<NSHTTPCookie *> *cookies) {
+                EXPECT_EQ(cookies.count, 1ull);
+                EXPECT_WK_STREQ(cookies[0].name, "webKitName");
+                [globalCookieStore _getCookiesForURL:[NSURL URLWithString:@"https://nonAppBoundDomain.com/"] completionHandler:^(NSArray<NSHTTPCookie *> *cookies) {
+                    EXPECT_EQ(cookies.count, 0u);
+                    [globalCookieStore deleteCookie:nonAppBoundCookie completionHandler:^{
+                        [globalCookieStore deleteCookie:appBoundCookie completionHandler:^{
+                            [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+                            cleanUpInAppBrowserPrivacyTestSettings();
+                            done = true;
+                        }];
+                    }];
+                }];
+            }];
+        }];
+    }];
+    TestWebKitAPI::Util::run(&done);
 }
 
 #endif // USE(APPLE_INTERNAL_SDK)