WebView - 原生桥

OWASP 类别:MASVS-PLATFORM:平台互动

概览

原生桥梁(有时称为 JavaScript 桥梁)是一种机制,可促进 WebView 与原生 Android 代码之间的通信,方法是使用 addJavascriptInterface 方法。这样便可实现双向 在 WebView 中运行的 JavaScript 代码与 Android 应用的 Java 代码addJavascriptInterface 方法公开了一个 Java 对象添加到 WebView 的所有框架,并且任何框架都可以访问对象名称 并对其调用方法不过,应用并没有任何 在 WebView 中验证调用帧的来源,从而提高安全性 因为内容的可信度仍然不确定。

原生桥也可以实现 HTML 消息通道,方法是使用 Android 的 WebViewCompat.postWebMessageWebMessagePort.postMessage,以便与 JavaScript 进行通信 Window.postMessageWebViewCompat.postWebMessageWebMessagePort.postMessage 可接受通过 Window.postMessage(将在 WebView 中执行)。

与原生桥接相关的风险有多个:

  • 基于 JavaScriptInterface 的桥: <ph type="x-smartling-placeholder">
      </ph>
    • addJavascriptInterface 方法会将提供的 Java 对象注入 每个帧(包括 iframe),这意味着它容易受到 恶意第三方将框架注入合法网站的攻击。 以 API 级别 16 或更低级别为目标平台的应用特别容易受到攻击,因为此方法可用于允许 JavaScript 控制主机应用。
    • 在支持原生桥接的 WebView 中反映不受信任的用户提供的内容 允许跨站脚本攻击 (XSS) 攻击。
  • 基于 MessageChannel 的网桥: <ph type="x-smartling-placeholder">
      </ph>
    • 未对消息通道端点进行源站检查意味着消息 (包括包含恶意代码的发件人在内)。
    • 可能会意外将 Java 公开给任意 JavaScript。

影响

addJavascriptInterfacepostWebMessagepostMessage 方法可以 被恶意行为者利用,以访问、操纵或注入他们控制的代码 转换为 WebView。这可能会导致用户被重定向到恶意网站、加载恶意内容,或者在其设备上运行恶意代码,从而提取敏感数据或提升权限。

风险:addJavascriptInterface 风险

WebView 可实现浏览器的基本功能,例如页面渲染、 导航和 JavaScript 执行。WebView 可在应用内使用,以便在 activity 布局中显示 Web 内容。使用 addJavascriptInterface 方法在 WebView 中实现原生桥接可能会导致跨站脚本 (XSS) 等安全问题,或者允许攻击者通过接口注入加载不受信任的内容,并以意想不到的方式操纵主机应用,使用主机应用的权限执行 Java 代码。

缓解措施

停用 JavaScript

在 WebView 不需要 JavaScript 的情况下,请勿在 WebSettings 中调用 setJavaScriptEnabled(例如,在显示静态 HTML 内容时)。默认情况下,WebView 中 JavaScript 执行功能处于停用状态。

在加载不受信任的内容时移除 JavaScript 接口

确保通过调用 JavaScript 接口中的对象来删除 removeJavascriptInterface,然后 WebView。例如,您可以在调用 shouldInterceptRequest 时执行此操作。

Kotlin

webView.removeJavascriptInterface("myObject")

Java

webView.removeJavascriptInterface("myObject");

仅通过 HTTPS 加载网络内容

如果您需要加载不受信任的内容,请确保 WebView 通过加密连接加载 Web 内容(另请参阅我们关于明文通信的准则)。禁止在以下位置执行初始网页加载 将 android:usesCleartextTraffic 设置为 false,从而 AndroidManifest 文件,或在网络安全设置中禁止 HTTP 流量 配置。如需了解详情,请参阅 usesCleartextTraffic 文档。

Xml

<application
    android:usesCleartextTraffic="false">
    <!-- Other application elements -->
</application>

确保在未加密的情况下不会进行重定向和进一步浏览应用 请查看 loadUrl 中的 HTTP 协议,或者 shouldInterceptRequest:

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 中加载了任何外部链接,请同时验证 scheme 和主机 (将网域列入许可名单)。所有不在许可名单中的网域都应改为由默认浏览器打开。

请勿加载不可信的内容

如果可能,请仅在 WebView 中加载严格限定范围的网址和归应用开发者所有的内容。

请勿泄露敏感数据

如果您的应用通过 WebView 访问敏感数据,请考虑先使用 clearCache 方法删除本地存储的所有文件,然后再使用 JavaScript 接口。您也可以使用服务器端标头(例如 no-store) 指明应用不应缓存特定内容。

请勿暴露敏感功能

如果您的应用需要敏感权限或收集敏感数据, 请确保通过应用内的代码调用该函数, 披露声明。避免对任何敏感操作或用户数据使用 JavaScript 接口。

以 API 级别 21 或更高级别为目标平台

使用 addJavascriptInterface 方法的一种安全方法是,通过确保仅在 API 级别为 21 或更高级别时调用该方法,以定位到 API 级别 21 或更高级别。在 API 21 之前,JavaScript 可以使用反射来访问注入对象的公共字段。


风险:MessageChannel 风险

postWebMessage()postMessage() 中缺少源站控制可能会导致 来拦截消息或向原生处理程序发送消息。

缓解措施

设置 postWebMessage()postMessage() 时,仅允许来自以下来源的邮件: 可信网域(避免使用 * 作为目标来源),而是改用 明确指定预期的发送网域。


资源