MASTG-TEST-0076: 测试 iOS WebView
此测试即将更新
此测试目前可使用,但将作为新的 OWASP MASTG v2 指南 的一部分进行全面修订。
通过提交 PR 来帮助我们:MASTG v1->v2 MASTG-TEST-0076: 测试 iOS WebViews (ios)
概述¶
静态分析¶
对于静态分析,我们将主要关注以下几点,并将 UIWebView
和 WKWebView
纳入范围。
- 识别 WebView 使用情况
- 测试 JavaScript 是否启用
- 测试混合内容
- 测试 WebView URI 操作
识别 WebView 使用情况¶
通过在 Xcode 中搜索来查找上述 WebView 类的用法。
在编译后的二进制文件中,您可以在其符号或字符串中搜索,例如使用 rabin2 像这样
UIWebView¶
$ rabin2 -zz ./WheresMyBrowser | egrep "UIWebView$"
489 0x0002fee9 0x10002fee9 9 10 (5.__TEXT.__cstring) ascii UIWebView
896 0x0003c813 0x0003c813 24 25 () ascii @_OBJC_CLASS_$_UIWebView
1754 0x00059599 0x00059599 23 24 () ascii _OBJC_CLASS_$_UIWebView
WKWebView¶
$ rabin2 -zz ./WheresMyBrowser | egrep "WKWebView$"
490 0x0002fef3 0x10002fef3 9 10 (5.__TEXT.__cstring) ascii WKWebView
625 0x00031670 0x100031670 17 18 (5.__TEXT.__cstring) ascii unwindToWKWebView
904 0x0003c960 0x0003c960 24 25 () ascii @_OBJC_CLASS_$_WKWebView
1757 0x000595e4 0x000595e4 23 24 () ascii _OBJC_CLASS_$_WKWebView
或者,您也可以搜索这些 WebView 类的已知方法。例如,搜索用于初始化 WKWebView 的方法 (init(frame:configuration:)
)
$ rabin2 -zzq ./WheresMyBrowser | egrep "WKWebView.*frame"
0x5c3ac 77 76 __T0So9WKWebViewCABSC6CGRectV5frame_So0aB13ConfigurationC13configurationtcfC
0x5d97a 79 78 __T0So9WKWebViewCABSC6CGRectV5frame_So0aB13ConfigurationC13configurationtcfcTO
0x6b5d5 77 76 __T0So9WKWebViewCABSC6CGRectV5frame_So0aB13ConfigurationC13configurationtcfC
0x6c3fa 79 78 __T0So9WKWebViewCABSC6CGRectV5frame_So0aB13ConfigurationC13configurationtcfcTO
您也可以 demangle 它
$ xcrun swift-demangle __T0So9WKWebViewCABSC6CGRectV5frame_So0aB13ConfigurationC13configurationtcfcTO
---> @nonobjc __C.WKWebView.init(frame: __C_Synthesized.CGRect,
configuration: __C.WKWebViewConfiguration) -> __C.WKWebView
测试 JavaScript 是否启用¶
首先,请记住,对于 UIWebView
,JavaScript 无法禁用。
对于 WKWebView
,作为最佳实践,除非明确要求,否则应禁用 JavaScript。要验证 JavaScript 是否已正确禁用,请在项目中搜索 WKPreferences
的用法,并确保 javaScriptEnabled
属性设置为 false
let webPreferences = WKPreferences()
webPreferences.javaScriptEnabled = false
如果只有编译后的二进制文件,您可以使用 rabin2 在其中搜索。
$ rabin2 -zz ./WheresMyBrowser | grep -i "javascriptenabled"
391 0x0002f2c7 0x10002f2c7 17 18 (4.__TEXT.__objc_methname) ascii javaScriptEnabled
392 0x0002f2d9 0x10002f2d9 21 22 (4.__TEXT.__objc_methname) ascii setJavaScriptEnabled:
如果定义了用户脚本,它们将继续运行,因为 javaScriptEnabled
属性不会影响它们。有关将用户脚本注入 WKWebViews 的更多信息,请参见 WKUserContentController
和 WKUserScript。
测试混合内容¶
与 UIWebView
不同,使用 WKWebView
时,可以检测 混合内容(从 HTTPS 页面加载的 HTTP 内容)。通过使用方法 hasOnlySecureContent
,可以验证页面上的所有资源是否都已通过安全加密的连接加载。来自 [#thiel2] 的这个示例(请参见第 159 页和 160 页)使用此方法来确保仅将通过 HTTPS 加载的内容显示给用户,否则会显示警报,告知用户检测到混合内容。
在编译后的二进制文件中,您可以使用 rabin2
$ rabin2 -zz ./WheresMyBrowser | grep -i "hasonlysecurecontent"
# nothing found
在这种情况下,该应用程序没有利用这一点。
此外,如果您有原始源代码或 IPA,则可以检查嵌入的 HTML 文件并验证它们是否不包含混合内容。在源代码中和标签属性中搜索 http://
,但请记住,这可能会给出误报,例如,找到一个包含 http://
在其 href
属性中的锚标记 <a>
并不总是表示混合内容问题。在 MDN Web Docs 中了解有关混合内容的更多信息。
测试 WebView URI 操作¶
确保用户的 WebView URI 不能被操作,以便加载 WebView 功能不需要的其他类型的资源。当 WebView 的内容从本地文件系统加载时,这可能会特别危险,允许用户导航到应用程序中的其他资源。
动态分析¶
对于动态分析,我们将解决静态分析中的相同点。
- 枚举 WebView 实例
- 测试 JavaScript 是否启用
- 测试混合内容
通过执行动态检测,可以识别 WebView 并在运行时获取其所有属性。当您没有原始源代码时,这非常有用。
对于以下示例,我们将继续使用 "Where's My Browser?" 应用程序和 Frida REPL。
枚举 WebView 实例¶
一旦您在应用程序中识别出一个 WebView,您可以检查堆以查找我们在上面看到的一个或多个 WebViews 的实例。
例如,如果您使用 Frida,您可以通过 "ObjC.choose()" 检查堆来做到这一点
ObjC.choose(ObjC.classes['UIWebView'], {
onMatch: function (ui) {
console.log('onMatch: ', ui);
console.log('URL: ', ui.request().toString());
},
onComplete: function () {
console.log('done for UIWebView!');
}
});
ObjC.choose(ObjC.classes['WKWebView'], {
onMatch: function (wk) {
console.log('onMatch: ', wk);
console.log('URL: ', wk.URL().toString());
},
onComplete: function () {
console.log('done for WKWebView!');
}
});
ObjC.choose(ObjC.classes['SFSafariViewController'], {
onMatch: function (sf) {
console.log('onMatch: ', sf);
},
onComplete: function () {
console.log('done for SFSafariViewController!');
}
});
对于 UIWebView
和 WKWebView
WebViews,为了完整起见,我们还打印相关的 URL。
为了确保您能够在堆中找到 WebViews 的实例,请务必首先导航到您找到的 WebView。到那里后,运行上面的代码,例如,通过复制到 Frida REPL
$ frida -U com.authenticationfailure.WheresMyBrowser
# copy the code and wait ...
onMatch: <UIWebView: 0x14fd25e50; frame = (0 126; 320 393);
autoresize = RM+BM; layer = <CALayer: 0x1c422d100>>
URL: <NSMutableURLRequest: 0x1c000ef00> {
URL: file:///var/mobile/Containers/Data/Application/A654D169-1DB7-429C-9DB9-A871389A8BAA/
Library/UIWebView/scenario1.html, Method GET, Headers {
Accept = (
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
);
"Upgrade-Insecure-Requests" = (
1
);
"User-Agent" = (
"Mozilla/5.0 (iPhone; CPU iPhone ... AppleWebKit/604.3.5 (KHTML, like Gecko) Mobile/..."
);
} }
现在我们用 q
退出并打开另一个 WebView(在本例中为 WKWebView
)。如果我们重复之前的步骤,它也会被检测到
$ frida -U com.authenticationfailure.WheresMyBrowser
# copy the code and wait ...
onMatch: <WKWebView: 0x1508b1200; frame = (0 0; 320 393); layer = <CALayer: 0x1c4238f20>>
URL: file:///var/mobile/Containers/Data/Application/A654D169-1DB7-429C-9DB9-A871389A8BAA/
Library/WKWebView/scenario1.html
我们将在以下各节中扩展此示例,以便从 WebViews 获取更多信息。我们建议将此代码存储到一个文件中,例如 webviews_inspector.js,并像这样运行它
frida -U com.authenticationfailure.WheresMyBrowser -l webviews_inspector.js
检查 JavaScript 是否启用¶
请记住,如果正在使用 UIWebView
,则默认启用 JavaScript,并且无法禁用它。
对于 WKWebView
,您应该验证是否启用了 JavaScript。为此,请使用来自 WKPreferences
的 javaScriptEnabled
。
使用以下行扩展先前的脚本
ObjC.choose(ObjC.classes['WKWebView'], {
onMatch: function (wk) {
console.log('onMatch: ', wk);
console.log('javaScriptEnabled:', wk.configuration().preferences().javaScriptEnabled());
//...
}
});
输出现在显示,实际上,JavaScript 已启用
$ frida -U com.authenticationfailure.WheresMyBrowser -l webviews_inspector.js
onMatch: <WKWebView: 0x1508b1200; frame = (0 0; 320 393); layer = <CALayer: 0x1c4238f20>>
javaScriptEnabled: true
测试混合内容¶
UIWebView
类不提供用于验证是否仅允许安全内容的方法。但是,从 iOS 10 开始,Upgrade-Insecure-Requests
CSP(内容安全策略)指令已引入 WebKit,这是为 iOS WebViews 提供支持的浏览器引擎。此指令可用于指示浏览器将不安全的请求升级为安全的请求。这是防止混合内容问题的一个好方法。
对于 WKWebView
's,您可以为堆中找到的每个 WKWebView
调用方法 hasOnlySecureContent
。请记住在 WebView 加载后执行此操作。
使用以下行扩展先前的脚本
ObjC.choose(ObjC.classes['WKWebView'], {
onMatch: function (wk) {
console.log('onMatch: ', wk);
console.log('hasOnlySecureContent: ', wk.hasOnlySecureContent().toString());
//...
}
});
输出显示页面上的一些资源已通过不安全的连接加载
$ frida -U com.authenticationfailure.WheresMyBrowser -l webviews_inspector.js
onMatch: <WKWebView: 0x1508b1200; frame = (0 0; 320 393); layer = <CALayer: 0x1c4238f20>>
hasOnlySecureContent: false