WebView - Ponti nativi

Categoria OWASP: MASVS-PLATFORM: Interazione con la piattaforma

Panoramica

Un bridge nativo, a volte noto come bridge JavaScript, è un meccanismo che facilita la comunicazione tra un componente WebView e il codice Android nativo, utilizzando il metodo addJavascriptInterface. In questo modo, è possibile comunicazione tra il codice JavaScript in esecuzione in WebView e in Android il codice Java dell'applicazione. Il metodo addJavascriptInterface espone un file Java a tutti i frame di un componente WebView e ogni frame può accedere al nome dell'oggetto e richiamare i metodi. Tuttavia, non esiste un meccanismo per consentire all'applicazione di verificare l'origine del frame di chiamata all'interno di WebView, il che solleva dubbi sulla sicurezza poiché l'attendibilità dei contenuti rimane indeterminata.

Un bridge nativo può essere implementato anche con i canali di messaggi HTML utilizzando WebViewCompat.postWebMessage di Android WebMessagePort.postMessage per comunicare con JavaScript Window.postMessage WebViewCompat.postWebMessage e WebMessagePort.postMessage può accettare messaggi JavaScript inviati tramite Window.postMessage che verrà eseguita all'interno della WebView.

Esistono diversi rischi associati ai bridge nativi:

  • Ponti basati su JavascriptInterface:
    • Il metodo addJavascriptInterface inserisce un oggetto Java fornito in ogni frame della WebView, inclusi gli iframe, il che significa che è suscettibile un attacco da parte di terze parti dannose che inseriscono frame in un sito web legittimo. Le applicazioni che hanno come target il livello API 16 o versioni precedenti sono particolarmente a rischio di perché questo metodo può essere usato per consentire a JavaScript di controllare un'applicazione.
    • La visualizzazione di contenuti forniti dall'utente non attendibili in WebView con bridge nativo consente attacchi di cross-site scripting (XSS).
  • Ponti basati su MessageChannel:
    • L'assenza di controlli dell'origine sugli endpoint dei canali di messaggi significa che i messaggi essere accettati da qualsiasi mittente, inclusi quelli contenenti codice dannoso.
    • È possibile esporre accidentalmente Java a JavaScript arbitrario.

Impatto

I metodi addJavascriptInterface, postWebMessage e postMessage possono essere utilizzati da malintenzionati per accedere, manipolare o iniettare codice controllato in un WebView. Gli utenti potrebbero essere reindirizzati a siti dannosi, caricare contenuti dannosi o eseguire codice dannoso sui propri dispositivi che può estrarre dati sensibili o ottenere l'escalation dei privilegi.

Rischio: rischi di addJavascriptInterface

WebView implementa funzionalità di base di un browser, come rendering delle pagine, navigazione ed esecuzione di JavaScript. WebView può essere utilizzato all'interno di un'applicazione per visualizzare contenuti web come parte di un layout di attività. L'implementazione di un bridge nativo all'interno di un WebView utilizzando il metodo addJavascriptInterface può creare problemi di sicurezza come cross-site scripting (XSS) o consentire agli utenti malintenzionati di caricare contenuti non attendibili tramite l'iniezione di interfaccia e manipolare l'applicazione host in modi indesiderati, eseguendo codice Java con le autorizzazioni dell'applicazione host.

Mitigazioni

Disattiva JavaScript

Negli scenari in cui WebView non richiede JavaScript, non chiamare setJavaScriptEnabled in WebSettings (ad esempio, mentre visualizzare contenuti HTML statici). Per impostazione predefinita, l'esecuzione di JavaScript è disattivata WebView.

Rimuovi l'interfaccia di JavaScript quando vengono caricati contenuti non attendibili

Assicurati che gli oggetti dall'interfaccia di JavaScript vengano rimossi chiamando removeJavascriptInterface prima del caricamento di contenuti non attendibili da parte dell' WebView. Ad esempio, questo può essere fatto in una chiamata a shouldInterceptRequest.

Kotlin

webView.removeJavascriptInterface("myObject")

Java

webView.removeJavascriptInterface("myObject");

Carica contenuti web solo tramite HTTPS

Se devi caricare contenuti non attendibili, assicurati che il componente WebView carichi contenuti web tramite Una connessione crittografata (vedi anche le nostre linee guida su Cleartext Comunicazioni). Per impedire il caricamento iniziale della pagina su connessioni non criptate, imposta android:usesCleartextTraffic su false nel file AndroidManifest o non consentire il traffico HTTP in una configurazione di sicurezza di rete. Per ulteriori informazioni, consulta la documentazione di usesCleartextTraffic.

Xml

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

Per garantire che i reindirizzamenti e la navigazione nelle app non si verifichino su pagine non criptate traffico, controlla lo schema HTTP in loadUrl 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);
        }
    }
}

Convalida contenuti non attendibili

Se in un componente WebView vengono caricati link esterni, convalida sia lo schema che l'host (domini nella lista consentita). Tutti i domini non inclusi nella lista consentita devono essere aperti dal browser predefinito.

Non caricare contenuti non attendibili

Se possibile, carica in WebView solo gli URL con ambito limitato e i contenuti di proprietà dello sviluppatore dell'app.

Non esporre dati sensibili

Se la tua applicazione accede a dati sensibili con un componente WebView, valuta la possibilità di utilizzare il clearCache per eliminare tutti i file archiviati localmente, prima di utilizzare il metodo nell'interfaccia di JavaScript. Puoi anche utilizzare le intestazioni lato server, come no-store, per indicare che un'applicazione non deve memorizzare nella cache determinati contenuti.

Non esporre funzionalità sensibili

Se la tua applicazione richiede autorizzazioni sensibili o raccoglie dati sensibili, assicurati che venga chiamato dal codice all'interno dell'applicazione e che le informazioni che l'informativa sia fornita agli utenti. Evita di utilizzare interfacce JavaScript per per operazioni o dati utente sensibili.

Livello API target 21 o superiore

Un modo sicuro per utilizzare il metodo addJavascriptInterface è scegliere come target il livello API 21 o versioni successive assicurandosi che il metodo venga chiamato solo quando viene eseguito a un livello API 21 o superiore. Prima dell'API 21, JavaScript poteva utilizzare la riflessione per accedere ai campi pubblici di un oggetto iniettato.


Rischio: rischi di MessageChannel

La mancanza di controllo dell'origine in postWebMessage() e postMessage() potrebbe consentire Gli utenti malintenzionati possono intercettare i messaggi o inviare messaggi a gestori nativi.

Mitigazioni

Quando configuri postWebMessage() o postMessage(), consenti solo i messaggi provenienti da ai domini attendibili evitando di utilizzare * come origine di destinazione specificare esplicitamente il dominio di invio previsto.


Risorse