应用绑定域

许多应用程序使用 WKWebView 作为一种便捷的方式来显示网站,而无需用户离开应用程序,这被称为应用内浏览。尽管这可以提供出色的用户体验,但 WKWebView 为开发者提供的强大功能使得宿主应用能够监视用户在应用内访问的所有网站。

强大的 WKWebView 功能,例如 JavaScript 注入、事件处理程序和其他 API,可能被应用程序或实用程序框架以侵入性方式使用,与已知跟踪器通信,以收集和汇总用户的个人信息。这些策略可以揭示用户停留在哪些图像上、复制/粘贴了哪些内容以及滚动到页面哪些部分。

对于 iOS 14.0 和 iPadOS 14.0,我们希望让开发者能够在不使用户面临跟踪风险的情况下继续提供应用内浏览体验。今天我们推出应用绑定域(App-Bound Domains),这是一种新的可选 WKWebView 技术,通过为用户提供更大的隐私来改善应用内浏览。

应用绑定域

应用绑定域功能通过限制应用程序可以使用强大 API 在应用内浏览期间跟踪用户的域,从而采取措施保护用户隐私。选择启用此新功能的应用程序可以使用新的 Info.plist 键 WKAppBoundDomains 指定最多 10 个“应用绑定”域。请注意,应用程序通过本地文件、数据 URL 和 HTML 字符串提供的内容始终被视为应用绑定域,无需列出。

<plist version="1.0">
<dict>
<key>WKAppBoundDomains</key>
<array>
    <string>example1.com</string>
    <string>example2.org</string>
    ...
</array>
</dict>

一旦 WKAppBoundDomains 键被添加到 Info.plist 中,应用程序中所有 WKWebView 实例将默认进入一个模式,在该模式下,JavaScript 注入、自定义样式表、Cookie 操作和消息处理程序的使用均被拒绝。要重新获得对这些 API 的访问权限,WKWebView 可以在其 WKWebView 配置中设置 limitsNavigationsToAppBoundDomains 标志,如下所示:

webViewConfiguration.limitsNavigationsToAppBoundDomains = YES;

设置此标志表示 WebKit,该 WKWebView 将只导航到应用绑定域。一旦设置,任何尝试导航离开应用绑定域的操作都将失败,并显示错误:“应用绑定域失败”。配置了此标志并从 WKAppBoundDomains 列表或本地资源(如文件 URL、数据 URL 和字符串)加载应用绑定域的网页视图将能够访问以下 API:

  • (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler
  • (void)addUserScript:(WKUserScript *)userScript;
  • window.webkit.messageHandlers

此外,应用程序将能够访问以下 WKHTTPCookieStore API,以访问应用绑定域的 Cookie:

  • (void)setCookie:(NSHTTPCookie *)cookie completionHandler:(nullable void (^)(void))completionHandler;
  • (void)getAllCookies:(void (^)(NSArray<NSHTTPCookie *> *))completionHandler;

所有其他 WKWebView 实例都无法使用这些 API,因为它们可能泄露私人数据。这使得导航到小范围应用绑定域之外的 WKWebView 更像 SafariViewController,后者已经内置了类似的隐私保护。

我们将在下面详细讨论应用绑定域的具体示例和优点。

示例用例

我们将使用五个例子来说明应用绑定域如何适应不同类型的应用程序:

  • UnchangedApp,一个未选择应用绑定域的应用程序。
  • ShopApp,一个仅包含自托管内容的应用程序。
  • SocialApp,一个带有应用内浏览器的应用程序。
  • BrowserApp,一个完整的网页浏览器应用程序。
  • HybridApp,一个同时包含自托管内容和应用内浏览器的应用程序。

UnchangedApp

首先,让我们考虑 UnchangedApp,它没有选择应用绑定域,也没有以任何方式改变其行为。UnchangedApp 将体验到 iOS 14.0 之前 WKWebView 的行为,在任何域上都没有受限的 API。然而,UnchangedApp 不采用应用绑定域的决定可能会使用户面临跟踪风险,例如,如果 UnchangedApp 包含第三方代码,而这些代码偷偷地向网页视图注入脚本。

ShopApp(自托管内容)

我们来看一个简单的应用程序 ShopApp 的例子,它只从自己的域 shop.example 提供网页内容。ShopApp 可以通过在 Info.plist 中创建一个新的数组条目,键为 WKAppBoundDomains 来选择启用应用绑定域。这类应用程序可以在数组中添加最多 10 个“应用绑定”域作为字符串。这可能是 ShopApp 的 Info.plist 条目的一个例子:

<plist version="1.0">
<dict>
<key>WKAppBoundDomains</key>
<array>
    <string>shop.example</string>
    <string>shop-cdn.example</string>
</array>
</dict>

为了让 WKWebView 在这些域上使用受限 API,ShopApp 还必须使用以下配置参数初始化 WKWebView

webViewConfiguration.limitsNavigationsToAppBoundDomains = YES;

现在,当 ShopApp 浏览 shop.example 和 shop-cdn.example 时,将能够访问上述所有 API。请注意,应用绑定域的检查只针对顶级框架进行,因此 ShopApp 仍然能够在 shop.example 上显示来自应用绑定域集之外的第三方 iframe。

SocialApp(带应用内浏览器)

现在让我们考虑一个社交媒体应用程序 SocialApp,它主要用作应用内浏览器。SocialApp 用户可能会使用该应用程序导航到许多不同的网站,在应用内浏览期间可能会遇到跟踪器 tracker.example。

如果没有应用绑定域提供的保护,SocialApp 可能会通过与 tracker.example 通信,以侵入性方式使用应用内浏览来跟踪用户。

如果 SocialApp 的开发者希望提供更好的用户隐私体验,他们有两种途径:

  1. 使用 SafariViewController 而不是 WKWebView 进行应用内浏览。SafariViewController 通过在 SocialApp 的进程空间之外加载页面来保护用户数据不被 SocialApp 访问。SocialApp 可以保证在使用 SafariViewController 时为用户提供最佳的用户隐私体验。
  2. 选择启用应用绑定域。应用绑定域带来的额外 WKWebView 限制确保 SocialApp 无法使用上述 API 跟踪用户。

要选择启用应用绑定域,SocialApp 只需在他们的 Info.plist 中添加一个空的 WKAppBoundDomains 键。

<plist version="1.0">
<dict>
<key>WKAppBoundDomains</key>
</dict>

由于 SocialApp 不需要任何受限 API,因此不需要任何 WKWebViewConfiguration 参数。

由于网络的异步特性,SocialApp 开发者如果在同一个 WKWebView 中尝试使用受限 API 并导航到非应用绑定域,可能会看到不同的错误。如果 SocialApp 中的 WKWebView 在任何导航发生之前使用了受限 API,然后尝试导航到“应用绑定”域集之外的域,导航将失败,并显示错误“App-bound domain failure。”相反,如果 SocialApp 首先导航到非应用绑定域,然后尝试使用受限 API,API 调用将失败。

BrowserApp(纯粹浏览网页)

另一个应用程序 BrowserApp 专门用于浏览网页。BrowserApp 之前已获得管理权限 com.apple.developer.web-browser,这表明其作为完整网页浏览器的用途。因此,BrowserApp 的所有 WKWebView 实例将在所有域上拥有不受限制的 API 访问权限。BrowserApp 不需要向其 Info.plist 添加 WKAppBoundDomains 值,也不需要对其初始化 WKWebView 的方式进行任何更改。

HybridApp(既有自托管内容又有应用内浏览器)

最后,让我们看一个更复杂的例子。HybridApp 是一个为用户提供应用内浏览的应用程序,但同时要求在它自己的域 hybrid.example 上,WKWebView 实例使用受限 API。HybridApp 是 ShopApp 和 SocialApp 的组合,在考虑 HybridApp 之前,您应该先阅读并完全理解这些例子。

HybridApp 的 Info.plist 可能看起来像这样:

<plist version="1.0">
<dict>
<key>WKAppBoundDomains</key>
<array>
    <string>hybrid.example</string>
</array>
</dict>

HybridApp 需要在 hybrid.example 上注入 JavaScript,所以它可能会创建一个带有特定参数的 WKWebViewConfigurationwebViewConfiguration.limitsNavigationsToAppBoundDomains = YES;

HybridApp 现在可以导航到 hybrid.example 并成功注入 JavaScript。

[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://hybrid.example"]];
[webView evaluateJavaScript:script completionHandler:^(id value, NSError *error) {
    if ([value isEqual:@"Successfully injected JavaScript"])
        // …
}];

假设 HybridApp 尝试使用此 WKWebView 导航到 shop.example。由于 shop.example 不是应用绑定域,这将导致导航失败。

相反,HybridApp 可以创建另一个没有 limitsNavigationsToAppBoundDomains 配置标志的 WKWebView。HybridApp 可以使用这个新的 WKWebView 导航到任何域,包括应用绑定域。但是,任何调用受限 API 的尝试都将失败。

其他选项

应用绑定域功能旨在实现在不牺牲用户隐私的情况下进行应用内浏览。

在 iOS 14 之前,保护应用程序内部网页内容的唯一方法是使用 SFSafariViewController 处理一般网页内容,或使用 ASWebAuthenticationSession 进行身份验证。我们仍然认为 SafariViewController 和 ASWebAuthenticationSession 是保护用户数据的最佳方式,因为它们是托管在应用程序之外的视图,使得应用程序无法查看或与这些视图的内容交互。如果开发者只是希望为了方便用户而显示网页内容,或者只希望支持基于网页的身份验证流程,那么 SafariViewController 和 ASWebAuthenticationSession 仍然是最佳选择。

WKWebView 中的智能跟踪预防

此外,在 iOS 14.0 和 macOS Big Sur 中,智能跟踪预防(ITP)默认在所有 WKWebView 应用程序中启用。要了解 ITP 如何保护用户免受网页跟踪,请查阅此文档

在某些极端情况下,用户可能需要禁用 ITP 保护,例如当依赖不受应用开发者控制的网页内容时。应用程序可以通过在 Info.plist 中为键 NSCrossWebsiteTrackingUsageDescription 添加一个用途字符串来表示需要允许用户禁用 ITP。当此键存在时,它会导致应用程序的设置屏幕显示一个用户控件来禁用 ITP。该设置无法通过 API 调用读取或更改。

请注意,获取新默认网络浏览器权限的应用程序始终在设置中有一个用户控件来禁用 ITP,并且不需要在其 Info.plist 中指定 NSCrossWebsiteTrackingUsageDescription 键。

反馈和 Bug 报告

如果您发现此功能在任何方面与解释不符,请在 https://bugs.webkit.org 提交 WebKit bug,并抄送 Brent Fulgham 和 Kate Cheney。如需反馈,请联系我们的网页布道师 Jon Davis