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://
ojavascript://
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