WebView: caricamento URI non sicuro

Categoria OWASP: MASVS-CODE: Code Quality

Panoramica

Il caricamento di URI non sicuri si verifica quando un'applicazione Android non riesce a valutare correttamente la validità di un URI prima di caricarlo in una WebView.

Il motivo alla base di questo tipo di vulnerabilità è che un URI è composto da più parti, di cui, come minimo, lo schema e l'host (della parte dell'autorità) devono essere verificati (ad es. inseriti nella lista consentita) prima che l'URI venga caricato in una WebView o utilizzato internamente dall'applicazione.

Gli errori più comuni includono:

  • Controllo dell'host, ma non dello schema, consentendo a un malintenzionato di utilizzare schemi come http://, content:// o javascript:// con un host autenticato.
  • Impossibilità di analizzare correttamente l'URI, soprattutto nei casi in cui l'URI viene ricevuto come stringa.
  • Convalida dello schema, ma non dell'host (convalida dell'host insufficiente).

Per quanto riguarda l'ultimo caso, ciò si verifica in genere quando l'applicazione deve consentire sottodomini arbitrari di un dominio principale. Pertanto, anche se il nome host è stato estratto correttamente, l'app utilizza metodi come startsWith, endsWith, o contains della classe java.lang.String per convalidare la presenza di un dominio principale nella sezione della stringa estratta. Se utilizzati in modo errato, questi metodi potrebbero portare a risultati errati e forzare l'applicazione a considerare attendibile in modo improprio un host potenzialmente dannoso.

Impatto

A seconda del contesto in cui viene utilizzato l'host, l'impatto può variare. Nei casi in cui il caricamento di un URI dannoso (ovvero uno che ha aggirato il filtro/la lista consentita) in un componente WebView potrebbe potenzialmente portare alla compromissione dell'account (ad es. tramite phishing), all'esecuzione di codice (ad es. caricamento di JavaScript dannoso) o alla compromissione del dispositivo (codice exploit fornito tramite collegamento ipertestuale).

Mitigazioni

Quando gestisci gli URI delle stringhe, è importante analizzare la stringa come URI e convalidare sia lo schema che l'host:

Kotlin

fun isUriTrusted(incomingUri: String, trustedHostName: String): Boolean {
    try {
        val uri = Uri.parse(incomingUri)
        return uri.scheme == "https" && uri.host == trustedHostName
    } catch (e: NullPointerException) {
        throw NullPointerException("incomingUri is null or not well-formed")
    }
}

Java

public static boolean isUriTrusted(String incomingUri, String trustedHostName)
    throws NullPointerException {
        try {
            Uri uri = Uri.parse(incomingUri);
            return uri.getScheme().equals("https") &&
            uri.getHost().equals(trustedHostName);
        } catch (NullPointerException e) {
            throw new NullPointerException(
                "incomingUri is null or not well-formed");
        }
    }

Per la convalida dell'host, dopo aver isolato la parte URI corrispondente, è importante convalidarla interamente (anziché parzialmente) per identificare con precisione se l'host è attendibile o meno. Quando l'utilizzo di metodi come startsWith o endsWith non può essere evitato, è importante utilizzare la sintassi corretta e non trascurare caratteri o simboli necessari (ad esempio, endsWith richiede il carattere "." prima del nome di dominio per una corrispondenza esatta). Se non tieni conto di questi caratteri, potresti ottenere corrispondenze imprecise e compromettere la sicurezza. Poiché i sottodomini possono essere nidificati all'infinito, la corrispondenza delle espressioni regolari non è una strategia consigliata per la convalida dei nomi host.

Collaboratori: Dimitrios Valsamaras e Michael Peck di Microsoft Threat Intelligence

Risorse