Kategoria OWASP: MASVS-PLATFORM: Platform Interaction
Przegląd
Most natywny, czasami nazywany mostem JavaScript, to mechanizm, który
ułatwia komunikację między komponentem WebView a natywnym kodem Androida. Jest to możliwe dzięki
użyciu 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 obiekt Java wszystkim ramkom komponentu WebView, a każda ramka może uzyskać dostęp do nazwy obiektu i wywoływać jego metody. Aplikacja nie ma jednak możliwości sprawdzenia pochodzenia ramki wywołującej w komponencie WebView, co budzi obawy dotyczące bezpieczeństwa, ponieważ wiarygodność treści pozostaje nieokreślona.
Most natywny można też zaimplementować za pomocą kanałów wiadomości HTML, używając
metod WebViewCompat.postWebMessage lub
WebMessagePort.postMessage do komunikacji z metodą JavaScript
Window.postMessage. Metody WebViewCompat.postWebMessage i WebMessagePort.postMessage mogą akceptować wiadomości JavaScript wysyłane za pomocą metody Window.postMessage, które będą wykonywane w komponencie WebView.
Z mostami natywnymi wiąże się kilka zagrożeń:
- Mosty oparte na JavascriptInterface:
- Metoda
addJavascriptInterfacewstrzykuje dostarczony obiekt Java do każdej ramki komponentu WebView, w tym do ramek iframe, co oznacza, że jest podatna na ataki złośliwych osób trzecich, które wstrzykują ramki do legalnej witryny. Aplikacje kierowane na poziom API 16 lub starszy są szczególnie narażone na ataki, ponieważ ta metoda może być używana do umożliwienia JavaScriptowi kontrolowania aplikacji hosta. - Odzwierciedlanie w komponentach WebView z włączonym mostem natywnym treści dostarczonych przez niezaufanych użytkowników umożliwia ataki typu cross-site scripting (XSS).
- Metoda
- Mosty oparte na MessageChannel:
- Brak sprawdzania pochodzenia w punktach końcowych kanału wiadomości oznacza, że wiadomości będą akceptowane od każdego nadawcy, w tym od tych, które zawierają złośliwy kod.
- Możliwe jest przypadkowe udostępnienie Javy dowolnemu JavaScriptowi.
Wpływ
Złośliwi użytkownicy mogą wykorzystać metody addJavascriptInterface, postWebMessage i postMessage, aby uzyskać dostęp do kodu, który kontrolują, manipulować nim lub wstrzykiwać go do komponentu WebView. Może to spowodować przekierowanie użytkowników do złośliwych witryn, wczytanie złośliwych treści lub uruchomienie na ich urządzeniach złośliwego kodu, który może wyodrębnić dane wrażliwe lub uzyskać eskalację uprawnień.
Ryzyko: zagrożenia związane z addJavascriptInterface
WebView implementuje podstawowe funkcje przeglądarki, takie jak renderowanie stron, nawigacja i wykonywanie JavaScriptu. WebView można używać w aplikacji do wyświetlania treści internetowych jako części układu aktywności. Implementowanie mostu natywnego w komponencie WebView za pomocą metody addJavascriptInterface może powodować problemy z bezpieczeństwem, takie jak ataki typu cross-site scripting (XSS), lub umożliwiać atakującym wczytywanie niezaufanych treści przez wstrzykiwanie interfejsu i manipulowanie aplikacją hosta w niepożądany sposób, wykonując kod Java z uprawnieniami aplikacji hosta.
Środki zaradcze
Wyłącz JavaScript
W sytuacjach, w których komponent WebView nie wymaga JavaScriptu, nie wywołuj
setJavaScriptEnabled w WebSettings (np. podczas
wyświetlania statycznej treści HTML). Domyślnie wykonywanie JavaScriptu jest w komponencie WebView wyłączone.
Usuń interfejs JavaScript podczas wczytywania niezaufanych treści
Zanim komponent
WebView wczyta niezaufane treści, usuń obiekty z interfejsu JavaScript, wywołując metodę
removeJavascriptInterface. Możesz to zrobić np. w wywołaniu metody
shouldInterceptRequest.
Kotlin
webView.removeJavascriptInterface("myObject")
Java
webView.removeJavascriptInterface("myObject");
Wczytuj treści internetowe tylko przez HTTPS
Jeśli musisz wczytać niezaufane treści, upewnij się, że komponent WebView wczytuje treści internetowe przez zaszyfrowane połączenie (zapoznaj się też z naszymi wytycznymi dotyczącymi komunikacji w postaci zwykłego tekstu). Aby zapobiec wczytywaniu początkowej strony przez niezaszyfrowane połączenia, ustaw android:usesCleartextTraffic na false w pliku AndroidManifest lub zablokuj ruch HTTP w konfiguracji zabezpieczeń sieciowych. Więcej informacji znajdziesz w dokumentacji usesCleartextTraffic.
XML
<application
android:usesCleartextTraffic="false">
<!-- Other application elements -->
</application>
Aby mieć pewność, że przekierowania i dalsze przeglądanie aplikacji nie będą odbywać się przez niezaszyfrowany
ruch, 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);
}
}
}
Sprawdź niezaufane treści
Jeśli w komponencie WebView wczytywane są linki zewnętrzne, sprawdź zarówno schemat, jak i hosta (domeny na liście dozwolonych). Wszystkie domeny, których nie ma na liście dozwolonych, powinny być otwierane w domyślnej przeglądarce.
Nie wczytuj niezaufanych treści
Jeśli to możliwe, wczytuj w komponencie WebView tylko adresy URL o ściśle określonym zakresie oraz treści należące do dewelopera aplikacji.
Nie udostępniaj informacji poufnych
Jeśli Twoja aplikacja uzyskuje dostęp do danych wrażliwych za pomocą komponentu WebView, przed użyciem interfejsu JavaScript rozważ użycie metody clearCache, aby usunąć wszystkie pliki przechowywane lokalnie. Możesz też użyć nagłówków po stronie serwera, np. no-store, aby wskazać, że aplikacja nie powinna zapisywać w pamięci podręcznej określonych treści.
Nie udostępniaj funkcji poufnych
Jeśli Twoja aplikacja wymaga uprawnień newralgicznych lub zbiera dane wrażliwe, upewnij się, że jest wywoływana z kodu w aplikacji i że użytkownicy są o tym wyraźnie informowani. Unikaj używania interfejsów JavaScript do operacji poufnych lub danych użytkownika.
Kieruj aplikację co najmniej na poziom API 21
Bezpiecznym sposobem używania metody addJavascriptInterface jest kierowanie aplikacji co najmniej na poziom API 21 przez zapewnienie, że metoda jest wywoływana tylko wtedy, gdy aplikacja działa na poziomie API 21 lub wyższym. Przed poziomem API 21 JavaScript mógł używać odbicia do uzyskiwania dostępu do pól publicznych wstrzykniętego obiektu.
Ryzyko: zagrożenia związane z MessageChannel
Brak kontroli pochodzenia w metodach postWebMessage() i postMessage() może umożliwić atakującym przechwytywanie wiadomości lub wysyłanie wiadomości do natywnych obsługi.
Środki zaradcze
Podczas konfigurowania metod postWebMessage() lub postMessage() zezwalaj tylko na wiadomości z zaufanych domen, unikając używania symbolu * jako docelowego pochodzenia, i zamiast tego wyraźnie określ oczekiwaną domenę wysyłającą.
Zasoby
- Sprawdzone metody dotyczące postMessage()
- Dokumentacja addJavascriptInterface
- Dokumentacja postMessage()
- Dokumentacja WebMessagePort.postMessage()
- Dokumentacja WebViewClient.shouldInterceptRequest
- Dokumentacja porad dotyczących bezpieczeństwa w odniesieniu do addJavascriptInterface
- Dokumentacja clearCache
- Dokumentacja removeJavascript
- Włączanie JavaScriptu w komponentach WebView