Перейти к содержанию

Возможность открытия произвольных данных в контексте WebView

Критичность: ВЫСОКИЙ
Способ обнаружения: IAST

Описание

WebView — это компонент, позволяющий отображать веб-страницы прямо внутри приложения. Приложение может использовать WebView для отображения HTML-контента или для интеграции веб-сервисов. Если данные, отображаемые в WebView, поступают от пользователя или стороннего приложения без должной проверки, это может привести к серьезным проблемам с безопасностью.

Пример использования WebView для загрузки данных из внешнего источника:

WebView myWebView = findViewById(R.id.webview);
String url = getIntent().getStringExtra("url");
myWebView.loadUrl(url);

В данном примере WebView загружает URL, который был передан из другого компонента. Это создает риск открытия произвольных данных, которые могут содержать вредоносный JavaScript или попытки получить доступ к локальным файлам.

Проблема

Если сторонние данные передаются в WebView без должной проверки, это может привести к следующим уязвимостям:

  1. Внедрение JavaScript (XSS) — Злоумышленник может передать вредоносный JavaScript-код, который будет выполнен в контексте WebView. Это может позволить злоумышленнику похитить данные, находящиеся в WebView, или получить доступ к чувствительной информации.
  2. Файловый доступ — Если WebView настроен на разрешение доступа к локальным файлам, злоумышленник может попытаться получить доступ к файловой системе устройства.
  3. Фишинг и обман пользователей — Злоумышленник может передать фишинговый URL, чтобы заставить пользователя ввести конфиденциальную информацию, такую как логин и пароль, на поддельной странице.
  4. Выполнение кода внутри приложения через JavaScript-интерфейс — Если в WebView используется JavaScript-интерфейс с методом addJavascriptInterface(), злоумышленник может вызвать код приложения, что может привести к выполнению произвольных команд. Это особенно опасно, если данные для WebView поступают из ненадежных источников.

Рекомендации

  1. Не используйте внешние данные без проверки для загрузки в WebView: Перед загрузкой данных в WebView убедитесь, что они проходят проверку и соответствуют требованиям безопасности. Используйте белый список (allow-list) разрешённых хостов и точную сверку, а не проверку по префиксу строки.

    Проверка вида url.startsWith("https://trusted-domain.com") небезопасна и легко обходится:

    • https://trusted-domain.com.evil.comevil.com является основным доменом, но строка начинается с ожидаемого префикса;
    • https://trusted-domain.com@evil.com — всё, что до символа @, является user-info, фактический хост — evil.com;
    • https://trusted-domain.com.evil.com/path и подобные комбинации.

    Корректный подход — разобрать URL через Uri.parse(...), проверить, что схема строго равна https, и что хост точно совпадает с одним из значений в белом списке (сравнение на равенство, а не на вхождение/префикс):

    import android.net.Uri;
    import java.util.Arrays;
    import java.util.HashSet;
    import java.util.Locale;
    import java.util.Set;
    
    private static final Set<String> ALLOWED_HOSTS = new HashSet<>(Arrays.asList(
            "trusted-domain.com",
            "www.trusted-domain.com"
    ));
    
    private boolean isUrlAllowed(String url) {
        if (url == null) {
            return false;
        }
        Uri uri = Uri.parse(url);
        String scheme = uri.getScheme();
        String host = uri.getHost();
        if (scheme == null || host == null) {
            return false;
        }
        // Схема строго https
        if (!"https".equals(scheme.toLowerCase(Locale.ROOT))) {
            return false;
        }
        // Точное совпадение хоста со значением из allow-list
        return ALLOWED_HOSTS.contains(host.toLowerCase(Locale.ROOT));
    }
    
    String url = getIntent().getStringExtra("url");
    if (isUrlAllowed(url)) {
        myWebView.loadUrl(url);
    } else {
        Log.e("WebView", "Неразрешенный URL");
    }
    

    В этом примере URL разбирается на компоненты, после чего отдельно проверяются схема (https) и хост (точное равенство значению из белого списка) перед загрузкой в WebView.

  2. Отключите JavaScript, если это возможно: Если нет необходимости в использовании JavaScript, его следует отключить, чтобы предотвратить возможное выполнение вредоносного кода. Это можно сделать с помощью настройки WebSettings:

    WebSettings webSettings = myWebView.getSettings();
    webSettings.setJavaScriptEnabled(false);
    
  3. Ограничьте доступ к локальным файлам: Убедитесь, что WebView не имеет доступа к локальным файлам, если это не требуется для работы приложения. Это можно сделать с помощью настройки:

    webSettings.setAllowFileAccess(false);
    webSettings.setAllowContentAccess(false);
    
  4. Используйте WebViewClient для обработки ссылок: Используйте собственный WebViewClient для обработки переходов по ссылкам. Это позволит контролировать, какие URL будут загружены, и предотвратить загрузку вредоносных страниц.

    Перегрузка shouldOverrideUrlLoading(WebView, String) объявлена устаревшей (deprecated) начиная с API 24 (Android 7.0). Используйте перегрузку, принимающую WebResourceRequest — из неё можно получить уже разобранный Uri запроса через request.getUrl() и применять ту же логику проверки (схема https + точная сверка хоста по белому списку):

    import android.webkit.WebResourceRequest;
    
    myWebView.setWebViewClient(new WebViewClient() {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            if (isUrlAllowed(request.getUrl().toString())) {
                return false; // Разрешить загрузку
            } else {
                Log.e("WebView", "Блокирован неразрешенный URL: " + request.getUrl());
                return true; // Блокировать загрузку
            }
        }
    });
    

    Здесь повторно используется метод isUrlAllowed(...) из примера выше, который проверяет схему и хост по белому списку.

  5. Очистите HTML-контент перед загрузкой: Если необходимо загрузить HTML-контент, который поступает от пользователя или другого приложения, используйте методы для очистки контента от возможных вредоносных вставок. Например, используйте библиотеки для фильтрации HTML, чтобы удалить вредоносный JavaScript.

  6. Избегайте использования JavaScript-интерфейса без должной необходимости: Если требуется использовать метод addJavascriptInterface(), убедитесь, что интерфейс безопасен и не предоставляет доступ к критическим методам или данным. Добавляйте интерфейсы только к проверенному контенту.

  7. Используйте безопасные настройки WebView: Отключите функции, которые могут повысить риск выполнения вредоносного кода или утечки данных:

    webSettings.setJavaScriptCanOpenWindowsAutomatically(false);
    webSettings.setDomStorageEnabled(false);
    webSettings.setAllowUniversalAccessFromFileURLs(false);
    webSettings.setAllowFileAccessFromFileURLs(false);
    

Дополнительные примеры

Пример небезопасного использования WebView для загрузки произвольного URL:

public void loadExternalUrl(String url) {
    myWebView.loadUrl(url);
}

В данном примере отсутствует проверка URL, что позволяет злоумышленнику передать вредоносный адрес для загрузки в WebView.

Ссылки

  1. WebView и безопасность
  2. Основы использования WebView
  3. Советы по безопасности WebView
  4. Ограничение доступа к файлам в WebView
  5. JavaScript-интерфейс и безопасность
К началу