OWASP 类别: MASVS-PLATFORM:平台交互
概述
原生桥接(有时也称为 JavaScript 桥接)是一种机制,用于促进 WebView 与原生 Android 代码之间的通信,通过使用 addJavascriptInterface
方法实现。这允许在 WebView 中运行的 JavaScript 代码与 Android 应用的 Java 代码之间进行双向通信。 addJavascriptInterface
方法将 Java 对象公开给 WebView 的所有框架,并且任何框架都可以访问对象名称并在其上调用方法。但是,应用无法验证 WebView 内调用框架的来源,这引发了安全问题,因为内容的可信度仍然是不确定的。
原生桥接也可以使用 HTML 消息通道与 Android 的 WebViewCompat.postWebMessage
或 WebMessagePort.postMessage
通信,以与 JavaScript Window.postMessage
通信。 WebViewCompat.postWebMessage
和 WebMessagePort.postMessage
可以接受通过 Window.postMessage
发送的 JavaScript 消息,这些消息将在 WebView 内执行。
原生桥接存在多种风险
- 基于 JavascriptInterface 的桥接
addJavascriptInterface
方法将提供的 Java 对象注入到 WebView 的每个框架中,包括 iframe,这意味着它容易受到恶意第三方将框架注入合法网站的攻击。面向 API 级别 16 或更低版本的应用尤其容易受到攻击,因为此方法可用于允许 JavaScript 控制主机应用。- 在启用原生桥接的 WebView 中反映不受信任的用户提供的内容会导致跨站点脚本 (XSS) 攻击。
- 基于 MessageChannel 的桥接
- 消息通道端点缺乏来源检查意味着将接受来自任何发送者的消息,包括包含恶意代码的消息。
- 可能会意外地将 Java 暴露给任意 JavaScript。
影响
恶意行为者可以利用 addJavascriptInterface
、postWebMessage
和 postMessage
方法来访问、操作或注入他们控制的代码到 WebView 中。这可能导致用户被重定向到恶意网站、加载恶意内容或在其设备上运行恶意代码,这些代码可以提取敏感数据或提升权限。
风险:addJavascriptInterface 风险
WebView 实现浏览器的基本功能,例如页面渲染、导航和 JavaScript 执行。WebView 可在应用内部使用,以将网络内容显示为活动布局的一部分。在 WebView 中使用 addJavascriptInterface
方法实现原生桥接可能会产生安全问题,例如跨站点脚本 (XSS),或允许攻击者通过接口注入加载不受信任的内容并以意外的方式操纵主机应用,使用主机应用的权限执行 Java 代码。
缓解措施
禁用 JavaScript
在WebView不需要JavaScript的情况下,不要在setJavaScriptEnabled
中调用WebSettings
(例如,在显示静态HTML内容时)。默认情况下,WebView中禁用了JavaScript执行。
加载不受信任的内容时移除JavaScript接口
确保在WebView加载不受信任的内容之前,通过调用removeJavascriptInterface
移除JavaScript接口中的对象。例如,这可以在调用shouldInterceptRequest
时完成。
Kotlin
webView.removeJavascriptInterface("myObject")
Java
webView.removeJavascriptInterface("myObject");
仅通过HTTPS加载网页内容
如果您需要加载不受信任的内容,请确保WebView通过加密连接加载网页内容(另请参阅我们关于明文通信的指南)。通过在AndroidManifest
文件中将android:usesCleartextTraffic
设置为false
或在网络安全配置中禁止HTTP流量来防止在未加密的连接上执行初始页面加载。有关更多信息,请参阅usesCleartextTraffic
文档。
Xml
<application
android:usesCleartextTraffic="false">
<!-- Other application elements -->
</application>
为了确保重定向和进一步的应用浏览不会在未加密的流量上发生,请在loadUrl
或shouldInterceptRequest
中检查HTTP方案。
Kotlin
fun loadSecureUrl(webView: WebView?, url: String?) {
webView?.let { wv -> // Ensure valid WebView and URL
url?.let {
try {
val uri = URI(url)
if (uri.scheme.equals("https", ignoreCase = true)) { // Enforce HTTPS scheme for security
wv.loadUrl(url)
} else {
// Log an error or handle the case where the URL is not secure
System.err.println("Attempted to load a non-HTTPS URL: $url")
}
} catch (e: Exception) {
// Handle exception for improper URL format
System.err.println("Invalid URL syntax: $url")
}
}
}
}
Java
public void loadSecureUrl(WebView webView, String url) {
if (webView != null && url != null) { // Ensure valid WebView and URL
try {
URI uri = new URI(url);
String scheme = uri.getScheme();
if ("https".equalsIgnoreCase(scheme)) { // Enforce HTTPS scheme for security
webView.loadUrl(url);
} else {
// Log an error or handle the case where the URL is not secure
System.err.println("Attempted to load a non-HTTPS URL: " + url);
}
} catch (URISyntaxException e) {
// Handle exception for improper URL format
System.err.println("Invalid URL syntax: " + url);
}
}
}
验证不受信任的内容
如果在WebView中加载了任何外部链接,请验证方案和主机(允许列表域名)。任何不在允许列表中的域名都应由默认浏览器打开。
不要加载不受信任的内容
如果可能,只将严格限定范围的URL和应用开发者拥有的内容加载到WebView中。
不要公开敏感数据
如果您的应用使用WebView访问敏感数据,请考虑使用clearCache
方法删除本地存储的任何文件,然后再使用JavaScript接口。您还可以使用服务器端标头(例如no-store)来指示应用不应缓存特定内容。
不要公开敏感功能
如果您的应用需要敏感权限或收集敏感数据,请确保它是在应用内的代码中调用的,并且向用户提供了明显的披露。避免使用JavaScript接口执行任何敏感操作或处理用户数据。
目标API级别为21或更高
使用addJavascriptInterface
方法的一种安全方式是将目标API级别设置为21或更高,方法是确保该方法仅在运行API级别21或更高版本时才被调用。在API 21之前,JavaScript可以使用反射访问注入对象的公共字段。
风险:MessageChannel风险
postWebMessage()
和postMessage()
中缺乏来源控制可能允许攻击者拦截消息或向本地处理程序发送消息。
缓解措施
在设置postWebMessage()
或postMessage()
时,只允许来自受信任域的消息,方法是避免使用*作为目标来源,而是显式指定预期的发送域。
资源
- postMessage()最佳实践
- addJavascriptInterface文档
- postMessage()文档
- WebMessagePort.postMessage()文档
- WebViewClient.shouldInterceptRequest文档
- 关于addJavascriptInterface的安全建议文档
- clearCache文档
- removeJavascript文档
- 在WebView中启用JavaScript