WebView – natywne mosty

Kategoria OWASP: MASVS-PLATFORM: Interakcja z platformą

Omówienie

Natywna usługa mostu, zwana też usługą mostu JavaScript, to mechanizm ułatwiający komunikację między WebView a natywnym kodem Androida. Aby go użyć, użyj metody addJavascriptInterface. Umożliwia to dwukierunkową komunikację między kodem JavaScript działającym w komponencie WebView a kodem Java aplikacji na Androida. Metoda addJavascriptInterface udostępnia środowisko Java do wszystkich ramek WebView, a każda ramka ma dostęp do nazwy obiektu i metod wywołania. Nie ma jednak mechanizmu, który pozwoliłby aplikacji zweryfikować pochodzenie wywołującej ramki w komponencie WebView. Powoduje to obawy dotyczące bezpieczeństwa, ponieważ nie można określić wiarygodności treści.

Most natywny można też zaimplementować za pomocą kanałów wiadomości HTML, używając WebViewCompat.postWebMessage lub WebMessagePort.postMessage na Androidzie do komunikacji z JavaScriptem Window.postMessage. WebViewCompat.postWebMessage i WebMessagePort.postMessage może akceptować wiadomości JavaScript wysyłane przez Window.postMessage, który zostanie uruchomiony w komponencie WebView.

Z użyciem mostów natywnych wiąże się kilka zagrożeń:

  • Mostki oparte na JavascriptInterface:
    • Metoda addJavascriptInterface wprowadza podany obiekt Java do każdej klatki komponentu WebView, w tym elementów iframe, co oznacza, że jest narażona na przez złośliwe osoby trzecie wstrzykujące ramki do wiarygodnej witryny. Aplikacje kierowane na interfejs API na poziomie 16 lub wyższym są szczególnie narażone na atak, ponieważ można użyć tej metody, aby umożliwić JavaScriptowi kontrolowanie hosta aplikacji.
    • Odzwierciedlenie niezaufanych treści przekazywanych przez użytkowników w natywnych komponentach WebView obsługujących mosty umożliwia ataki typu cross-site scripting (XSS).
  • Mosty oparte na MessageChannel:
    • Brak weryfikacji pochodzenia na punktach końcowych kanału wiadomości oznacza, że wiadomości będą akceptowane od dowolnego nadawcy, w tym tych zawierających złośliwy kod.
    • Istnieje ryzyko przypadkowego ujawnienia Javy dla dowolnego JavaScriptu.

Wpływ

Metody addJavascriptInterface, postWebMessage i postMessage mogą być wykorzystywane przez złośliwe podmioty w celu uzyskania dostępu do kontrolowanego przez siebie kodu, manipulowania nim lub wstrzykiwania w komponencie WebView. Może to prowadzić do przekierowywania użytkowników do szkodliwych witryn, wczytywania szkodliwych treści lub uruchamiania na urządzeniach szkodliwego kodu, który może wydobyć dane poufne lub uzyskać dostęp do uprawnień.

Zagrożenie: zagrożenia związane z metodą addJavascriptInterface

WebView implementuje podstawowe funkcje przeglądarki, takie jak renderowanie stron, nawigacji i wykonania JavaScriptu. Komponent WebView można używać w aplikacji wyświetlanie treści z internetu w ramach układu aktywności. Wdrażanie reklam natywnych mostu w komponencie WebView przy użyciu metody addJavascriptInterface może tworzyć problemy z bezpieczeństwem, np. ataki typu cross-site scripting (XSS), lub które umożliwiają hakerom wczytanie niezaufanych treści poprzez wstrzykiwanie kodu do interfejsu i manipulowanie hostem niezamierzonego uruchomienia kodu w Javie z użyciem uprawnień aplikacji hosta.

Łagodzenie

Wyłącz JavaScript

W sytuacjach, gdy komponent WebView nie wymaga JavaScriptu, nie wywołuj metody setJavaScriptEnabled w komponencie WebSettings (np. podczas wyświetlania statycznych treści HTML). Domyślnie wykonywanie kodu JavaScript jest wyłączone w WebView.

Usuń interfejs JavaScript podczas wczytywania niezaufanych treści

Przed wczytaniem niezaufanych treści przez komponent WebView usuń obiekty z interfejsu JavaScript, wywołując metodę removeJavascriptInterface. Można to zrobić na przykład w wywołaniu funkcji shouldInterceptRequest

Kotlin

webView.removeJavascriptInterface("myObject")

Java

webView.removeJavascriptInterface("myObject");

Ładuj treści internetowe tylko przez HTTPS

Jeśli chcesz wczytać niezaufane treści, upewnij się, że komponent WebView wczytuje treści z internetu: połączenia zaszyfrowanego (przeczytaj też nasze wytyczne na temat Cleartext Komunikacja). Nie zezwalaj na początkowe wczytywanie strony niezaszyfrowane połączenia przez ustawienie android:usesCleartextTraffic na false w AndroidManifest lub nie zezwalaj na ruch HTTP z zastosowaniem zabezpieczeń sieciowych config. Więcej informacji znajdziesz w dokumentacji usesCleartextTraffic.

XML

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

Aby mieć pewność, że w przypadku niezaszyfrowanego przekierowania nie będą występować przekierowania i dalsze przeglądanie aplikacji ruchu, sprawdź schemat HTTP w loadUrl lub 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);
        }
    }
}

Sprawdzanie niesprawdzonych treści

Jeśli jakieś linki zewnętrzne są wczytane w komponencie WebView, zweryfikuj zarówno schemat, jak i hosta (domeny z listy dozwolonych). Domeny, które nie znajdują się na liście dozwolonych, powinny być otwierane przez domyślną przeglądarkę.

Nie wczytuj niesprawdzonych treści

W miarę możliwości wczytuj w komponencie WebView tylko adresy URL o ściśle określonym zakresie oraz treści należące do dewelopera aplikacji.

Nie udostępniaj danych wrażliwych

Jeśli Twoja aplikacja uzyskuje dostęp do danych wrażliwych za pomocą komponentu WebView, zastosuj clearCache, by usunąć pliki przechowywane lokalnie, zanim użyjesz Interfejs JavaScript. Możesz też używać nagłówków po stronie serwera, takich jak no-store, aby wskazać, że aplikacja nie powinna przechowywać w pamięci podręcznej określonych treści.

Nie ujawniaj poufnych funkcji

Jeśli aplikacja wymaga uprawnień newralgicznych lub zbiera dane poufne, musisz zadbać o to, aby były wywoływane z kodu w aplikacji, oraz o to, aby użytkownicy byli wyraźnie informowani o ich dostępie do tych danych. Unikaj używania interfejsów JavaScript do wykonywania operacji na danych poufnych lub danych użytkownika.

Docelowy poziom interfejsu API 21 lub wyższy

Jednym ze sposobów bezpiecznego korzystania z metody addJavascriptInterface jest kierowanie na poziom interfejsu API 21 lub wyższy. Aby to zrobić, zadbaj o to, aby metoda była wywoływana tylko wtedy, gdy działa na poziomie interfejsu API 21 lub wyższym. Przed wersją 21 interfejsu API kod JavaScript mógł używać odbicia do uzyskiwania dostępu do publicznych pól wstrzykniętego obiektu.


Ryzyko: ryzyko związane z kanałem wiadomości

Brak kontroli pochodzenia w funkcjach postWebMessage()postMessage() może umożliwiać atakującym przechwytywanie wiadomości lub wysyłanie ich do natywnych modułów obsługi.

Łagodzenie

Podczas konfigurowania postWebMessage() lub postMessage() zezwalaj tylko na wiadomości z zaufanych domen, unikając użycia * jako docelowego źródła. Zamiast tego wyraźnie określ oczekiwaną domenę nadawcy.


Materiały