WebView – native Brücken

OWASP-Kategorie: MASVS-PLATFORM: Platform Interaction

Übersicht

Eine native Bridge, manchmal auch als JavaScript-Bridge bezeichnet, ist ein Mechanismus, der die Kommunikation zwischen einer WebView und nativem Android-Code mithilfe der Methode addJavascriptInterface ermöglicht. So kann eine bidirektionale Kommunikation zwischen JavaScript-Code, der in der WebView ausgeführt wird, und dem Java-Code der Android-Anwendung stattfinden. Die Methode addJavascriptInterface macht ein Java-Objekt für alle Frames einer WebView verfügbar. Jeder Frame kann auf den Objektnamen zugreifen und Methoden dafür aufrufen. Es gibt jedoch keinen Mechanismus, mit dem die Anwendung den Ursprung des aufrufenden Frames in der WebView überprüfen kann. Das birgt Sicherheitsrisiken, da die Vertrauenswürdigkeit des Inhalts unbestimmt bleibt.

Eine native Bridge kann auch mit HTML-Nachrichtenkanälen implementiert werden. Dazu wird Androids WebViewCompat.postWebMessage oder WebMessagePort.postMessage verwendet, um mit dem JavaScript Window.postMessage zu kommunizieren. WebViewCompat.postWebMessage und WebMessagePort.postMessage können JavaScript-Nachrichten akzeptieren, die über Window.postMessage gesendet werden und in der WebView ausgeführt werden.

Mit nativen Bridges sind mehrere Risiken verbunden:

  • Bridges auf Basis von JavascriptInterface:
    • Die Methode addJavascriptInterface fügt ein bereitgestelltes Java-Objekt in jeden Frame der WebView ein, einschließlich iFrames. Das bedeutet, dass sie anfällig für Angriffe durch böswillige Dritte ist, die Frames in eine legitime Website einfügen. Anwendungen, die auf API-Level 16 oder niedriger ausgerichtet sind, sind besonders anfällig für Angriffe, da mit dieser Methode JavaScript die Hostanwendung steuern kann.
    • Wenn nicht vertrauenswürdige, von Nutzern bereitgestellte Inhalte in WebViews mit aktivierter nativer Bridge wiedergegeben werden, sind Cross-Site-Scripting-Angriffe (XSS) möglich.
  • Bridges auf Basis von MessageChannel:
    • Wenn keine Ursprungsprüfungen für Endpunkte von Nachrichtenkanälen durchgeführt werden, werden Nachrichten von jedem Absender akzeptiert, auch solche, die schädlichen Code enthalten.
    • Es ist möglich, Java versehentlich für beliebiges JavaScript verfügbar zu machen.

Auswirkungen

Böswillige Akteure können die Methoden addJavascriptInterface, postWebMessage und postMessage nutzen, um auf eine WebView zuzugreifen, sie zu manipulieren oder von ihnen kontrollierten Code einzuschleusen. Das kann dazu führen, dass Nutzer auf schädliche Websites weitergeleitet werden, schädliche Inhalte geladen werden oder schädlicher Code auf ihren Geräten ausgeführt wird, der vertrauliche Daten extrahieren oder Rechteausweitung erzielen kann.

Risiko: Risiken von addJavascriptInterface

WebView implementiert grundlegende Funktionen eines Browsers wie Seitenrendering, Navigation und JavaScript-Ausführung. WebView kann in einer Anwendung verwendet werden, um Webinhalte als Teil eines Aktivitätslayouts anzuzeigen. Wenn Sie eine native Bridge in einer WebView mit der Methode addJavascriptInterface implementieren, können Sicherheitsprobleme wie Cross-Site-Scripting (XSS) entstehen. Angreifer können auch nicht vertrauenswürdige Inhalte über die Schnittstelleneinschleusung laden und die Hostanwendung auf unbeabsichtigte Weise manipulieren, indem sie Java-Code mit den Berechtigungen der Hostanwendung ausführen.

Gegenmaßnahmen

JavaScript deaktivieren

In Szenarien, in denen WebView kein JavaScript benötigt, rufen Sie setJavaScriptEnabled nicht in WebSettings auf (z. B. beim Anzeigen statischer HTML-Inhalte). Standardmäßig ist die JavaScript-Ausführung in WebView deaktiviert.

JavaScript-Schnittstelle beim Laden nicht vertrauenswürdiger Inhalte entfernen

Achten Sie darauf, dass Objekte aus der JavaScript-Schnittstelle entfernt werden, indem Sie removeJavascriptInterface aufrufen, bevor nicht vertrauenswürdige Inhalte von der WebView geladen werden. Das kann beispielsweise in einem Aufruf von shouldInterceptRequest erfolgen.

Kotlin

webView.removeJavascriptInterface("myObject")

Java

webView.removeJavascriptInterface("myObject");

Webinhalte nur über HTTPS laden

Wenn Sie nicht vertrauenswürdige Inhalte laden müssen, achten Sie darauf, dass die WebView Webinhalte über eine verschlüsselte Verbindung lädt (siehe auch unsere Richtlinien zu Cleartext Communications). Verhindern Sie, dass der anfängliche Seitenaufbau über unverschlüsselte Verbindungen durchgeführt wird, indem Sie android:usesCleartextTraffic auf false in der AndroidManifest Datei setzen oder HTTP-Traffic in einer Netzwerksicherheitskonfiguration deaktivieren. Weitere Informationen finden Sie in der usesCleartextTraffic Dokumentation zu mehr Informationen.

XML

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

Damit Weiterleitungen und weiteres Browsen in der App nicht über unverschlüsselten Traffic erfolgen, prüfen Sie das HTTP-Schema in loadUrl oder 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);
        }
    }
}

Nicht vertrauenswürdige Inhalte validieren

Wenn externe Links in einer WebView geladen werden, validieren Sie sowohl das Schema als auch den Host (Domains auf die Zulassungsliste setzen). Alle Domains, die nicht auf der Zulassungsliste stehen, sollten stattdessen vom Standardbrowser geöffnet werden.

Nicht vertrauenswürdige Inhalte nicht laden

Laden Sie nach Möglichkeit nur streng skalierte URLs und Inhalte, die dem App-Entwickler gehören, in die WebView.

Keine vertraulichen Daten verfügbar machen

Wenn Ihre Anwendung mit einer WebView auf vertrauliche Daten zugreift, sollten Sie die clearCache Methode verwenden, um alle lokal gespeicherten Dateien zu löschen, bevor Sie die JavaScript-Schnittstelle verwenden. Sie können auch serverseitige Header wie „no-store“ verwenden, um anzugeben, dass eine Anwendung bestimmte Inhalte nicht im Cache speichern soll.

Keine vertraulichen Funktionen verfügbar machen

Wenn Ihre Anwendung vertrauliche Berechtigungen erfordert oder vertrauliche Daten erfasst, achten Sie darauf, dass sie aus Code in der Anwendung aufgerufen wird und dass Nutzer deutlich darüber informiert werden. Verwenden Sie keine JavaScript-Schnittstellen für vertrauliche Vorgänge oder Nutzerdaten.

Auf API-Level 21 oder höher ausrichten

Eine sichere Möglichkeit, die Methode addJavascriptInterface zu verwenden, besteht darin, auf API-Level 21 oder höher auszurichten und sicherzustellen, dass die Methode nur aufgerufen wird, wenn sie auf API-Level 21 oder höher ausgeführt wird. Vor API-Level 21 konnte JavaScript die Reflektion verwenden, um auf die öffentlichen Felder eines eingefügten Objekts zuzugreifen.


Risiko: Risiken von MessageChannel

Wenn die Ursprungsprüfung in postWebMessage() und postMessage() fehlt, können Angreifer Nachrichten abfangen oder Nachrichten an native Handler senden.

Gegenmaßnahmen

Wenn Sie postWebMessage() oder postMessage() einrichten, lassen Sie nur Nachrichten von vertrauenswürdigen Domains zu. Verwenden Sie dazu nicht * als Zielursprung, sondern geben Sie stattdessen explizit die erwartete Absenderdomain an.


Ressourcen