Категория OWASP: MASVS-CODE: Качество кода
Обзор
Ошибка "Небезопасная загрузка URI" возникает, когда приложение Android не может корректно оценить допустимость URI перед загрузкой его в WebView.
Основная причина такого рода уязвимости заключается в том, что URI состоит из нескольких частей , из которых, как минимум, схема и хост (часть, отвечающая за авторизацию) должны быть проверены (например, внесены в список разрешенных) до того, как URI будет загружен в WebView или использован внутри приложения.
К наиболее распространенным ошибкам относятся:
- Проверка хоста, но не схемы, позволяет злоумышленнику использовать схемы типа
http://,content://илиjavascript://с аутентифицированным хостом. - Неправильный анализ URI, особенно в случаях, когда URI получен в виде строки.
- Проверка схемы, но не хоста (недостаточная проверка хоста).
Что касается последнего случая, он обычно возникает, когда приложению необходимо разрешить произвольные поддомены основного домена. Таким образом, даже если имя хоста было извлечено правильно, приложение использует такие методы, как startsWith , endsWith, или contains класса java.lang.String , для проверки наличия основного домена в извлеченной строковой части. Неправильное использование этих методов может привести к ошибочным результатам и заставить приложение некорректно доверять потенциально вредоносному хосту.
Влияние
В зависимости от контекста использования хоста, последствия могут быть различными. В случаях, когда загрузка вредоносного URI (т.е., обходящего фильтрацию/список разрешенных адресов) в WebView потенциально может привести к захвату учетной записи (например, с помощью фишинга), выполнению кода (например, загрузке вредоносного JavaScript) или компрометации устройства (код эксплойта, распространяемый через гиперссылку).
Меры по смягчению последствий
При обработке строковых URI важно интерпретировать строку как URI и проверить как схему, так и хост:
Котлин
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");
}
}
Для проверки хоста после выделения соответствующей части URI важно проверить её полностью (а не частично), чтобы точно определить, является ли хост доверенным или нет. Когда использование таких методов, как startsWith или endsWith неизбежно, важно использовать правильный синтаксис и не упускать из виду необходимые символы (например, endsWith требует наличия точки " . " перед именем домена для точного совпадения). Игнорирование этих символов может привести к неточным совпадениям и поставить под угрозу безопасность. Поскольку поддомены могут быть бесконечно вложенными, сопоставление с помощью регулярных выражений не является рекомендуемой стратегией для проверки имен хостов.
Авторы: Димитриос Вальсамарас и Майкл Пек из отдела анализа угроз Microsoft.