Как защитить приложение от атак через уязвимости в Microsoft Edge WebView2

Как защитить приложение от атак через уязвимости в Microsoft Edge WebView2

Вы разрабатываете десктопное приложение на .NET, WPF или WinForms и используете WebView2 для отображения веб-контента — например, интерфейса на React, админ-панель или встроенный браузер для загрузки внешних данных. Всё работает. Но недавно вы услышали, что в WebView2 есть уязвимости, которые могут позволить злоумышленнику выполнить код на машине пользователя. И теперь вы спрашиваете: «Что именно делать, чтобы моё приложение не стало точкой входа для атаки?»

Это не теоретический вопрос. Это реальная угроза. Уязвимости в WebView2 — не редкость. В 2023 году было зафиксировано несколько критических CVE, где атакующий мог обойти CORS, внедрить вредоносный JavaScript или даже получить доступ к файловой системе через специально сформированный HTML-контент. И если вы просто вставили WebView2 в приложение и забыли про него — вы рискуете.

В этой статье я расскажу, как реально защитить приложение — не теоретически, а по шагам, как делают в продакшене. Без воды, без пересказа документации Microsoft. Только то, что работает.

Что именно ломается в WebView2?

WebView2 — это обёртка над движком Chromium. То есть под капотом у вас тот же браузер, что и в Microsoft Edge. И он, как любой браузер, восприимчив к тем же атакам: XSS, CSRF, SSRF, неправильная изоляция контекста, утечка данных через JavaScript-инъекции.

Но есть важное отличие: в обычном браузере пользователь сам выбирает, куда заходит. В вашем приложении — нет. Вы сами загружаете контент. И если вы загружаете что-то из ненадёжного источника — например, внешний URL, пользовательский HTML, или даже динамически сгенерированный шаблон — вы открываете дверь.

Типичные сценарии атак:

  • Пользователь загружает HTML-файл с USB-накопителя — в нём есть JavaScript, который читает файлы из %APPDATA%.
  • Ваше приложение подгружает конфигурацию с сервера, и злоумышленник перехватил соединение — в ответ пришёл вредоносный HTML с eval() и require('fs') через Node.js-подобные хаки.
  • Вы используете ExecuteScriptAsync() для передачи данных из C# в JavaScript, но не валидируете аргументы — атакующий вставляет код через параметр URL.

Всё это — не теория. Я видел, как один из клиентов потерял данные сотен пользователей из-за того, что в приложении отображался HTML-шаблон, приходящий с внешнего API. Без фильтрации. Без изоляции. Без ограничений.

Какие методы защиты работают на практике

Защита от атак в WebView2 — это не одна настройка. Это слой мер. Вот что реально помогает.

1. Ограничьте источники контента

Никогда не загружайте произвольные URL. Даже если они «ваши».

Используйте CoreWebView2Settings.IsWebMessageEnabled и CoreWebView2Settings.AreDefaultScriptDialogsEnabled только если действительно нужны. А лучше — отключите всё, что не используется.

Важно: не используйте NavigateToString() с пользовательским вводом. Даже если вы «экранируете» теги — это не надёжно. Браузерные движки умнее, чем вы думаете.

Вместо этого — загружайте только локальные файлы или URL из доверенных доменов:

// Правильно: только локальный HTML
webView.CoreWebView2.Navigate("ms-appx-web:///Assets/index.html");

// Правильно: только конкретный домен
webView.CoreWebView2.Navigate("https://your-trusted-domain.com/dashboard");

// НЕ ПРАВИЛЬНО: пользовательский ввод
webView.CoreWebView2.Navigate(userInputUrl); // Это опасно!

Если вы вынуждены загружать внешние ресурсы — используйте Content Security Policy (CSP). Настройте его через HTTP-заголовки, если сервер ваш, или через ExecuteScriptAsync() при загрузке страницы:

await webView.CoreWebView2.ExecuteScriptAsync(@"
  const meta = document.createElement('meta');
  meta.httpEquiv = 'Content-Security-Policy';
  meta.content = 'default-src 'none'; script-src 'self'; style-src 'self'; object-src 'none';';
  document.head.appendChild(meta);
");

Это блокирует inline-скрипты, eval, внешние источники. Даже если кто-то внедрит JS — он не сработает.

2. Изолируйте контекст

WebView2 по умолчанию работает в одном контексте с вашим приложением. Это значит: если скрипт на странице получит доступ к window.chrome или window.external — он может вызывать методы .NET через window.chrome.webview.postMessage().

Чтобы этого не случилось — отключите доступ к WinRT и .NET API.

В коде инициализации WebView2 добавьте:

webView.CoreWebView2.Settings.AreDevToolsEnabled = false;
webView.CoreWebView2.Settings.IsWebMessageEnabled = false;
webView.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false;
webView.CoreWebView2.Settings.AreHostObjectsAllowed = false;
webView.CoreWebView2.Settings.IsScriptEnabled = false; // если не нужен JS вообще

Если вам нужен JavaScript — включите его, но только после настройки CSP и изоляции.

Если вы используете PostWebMessageAsJson() — всегда валидируйте входящие сообщения. Не доверяйте ни одному полю. Проверяйте:

  • тип данных (строка, число, объект)
  • допустимые значения (например, только «login», «logout», «get-data»)
  • длину строки (не более 1000 символов)
  • отсутствие тегов, скобок, escape-последовательностей

Пример валидации:

private void OnWebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e)
{
    var message = e.WebMessageAsJson;
    if (message == null || !message.ContainsKey("action")) return;

    var action = message["action"]?.ToString();
    if (action == null || !new[] { "load-data", "submit-form" }.Contains(action)) return;

    // Только после валидации — обрабатываем
    HandleAction(action);
}

3. Не используйте WebView2 для отображения пользовательского контента

Если ваше приложение позволяет пользователям загружать HTML-файлы, редактировать шаблоны, вставлять код — не используйте WebView2 для этого.

WebView2 — не редактор, не песочница. Он не предназначен для отображения непроверенного контента. Даже с CSP и изоляцией — есть риски, связанные с обходом изоляции через уязвимости в Chromium.

Если вам нужно отображать пользовательский HTML — используйте:

  • HTML-парсеры (например, AngleSharp) для санитизации
  • Плагины типа Microsoft.WebView2 с ограниченным набором тегов
  • Собственные компоненты на базе SkiaSharp или другого рендерера

Если вы всё же используете WebView2 — загружайте только статические, предварительно проверенные шаблоны, хранящиеся в приложении. Не динамически генерируемые, не приходящие с сервера без проверки.

4. Обновляйте WebView2 автоматически

Уязвимости в WebView2 исправляются с обновлениями Edge. Но если ваше приложение использует статическую версию WebView2 (например, установленную через MSI), оно может оставаться уязвимым даже после обновления системы.

Решение: используйте онлайн-распространение (per-user or per-machine runtime).

Вот как это работает:

  1. Установите WebView2 Runtime через официальный установщик — это не обязательно, но желательно.
  2. В вашем приложении используйте CoreWebView2Environment.CreateAsync() без указания пути — тогда будет использоваться последняя установленная версия Edge.
  3. Или — упакуйте WebView2 Runtime вместе с вашим приложением через приложенный runtime.

Почему это важно? В 2023 году уязвимость CVE-2023-21834 позволяла обойти CORS через специальный URL-запрос. Она была исправлена в версии 111.0.1661.51. Если ваше приложение использовало старую версию — пользователи были уязвимы месяцами. Даже если они обновили Edge — ваше приложение могло использовать старый движок.

Что выбрать: статический контент или динамический?

Вот таблица, которая поможет выбрать подход под вашу ситуацию.

Сценарий Подход Риски Рекомендуемая защита
Отображение внутренней веб-панели (ваш сайт) Загрузка из доверенного домена Сервер скомпрометирован, отдаёт вредоносный HTML CSP + HTTPS + проверка сертификата + отключить JS, если не нужен
Показ статического HTML-шаблона (например, справка) Локальный файл в приложении Файл повреждён или подменён Проверка хеша файла при запуске + цифровая подпись
Отображение пользовательского HTML (например, письмо) Не использовать WebView2 Высокий риск: XSS, кража данных, выполнение кода Использовать AngleSharp + санитизация + рендеринг в собственном контроле
Интеграция с внешним API (данные приходят с сервера) Загрузка через HTTPS, только JSON MITM-атака, подмена ответа Pinning сертификата + проверка ответа на структуру + фильтрация перед вставкой
Приложение с возможностью загрузки плагинов Изолированный WebView2 в отдельном процессе Плагин содержит вредоносный код Использовать CoreWebView2Environment с отдельной папкой профиля + ограничение прав доступа

Если вы не уверены — выбирайте статический контент. Он безопаснее. Всегда.

Частые ошибки, которые ломают защиту

Я видел десятки приложений, где всё «настроено», но всё равно ломается. Вот что чаще всего идёт не так:

  • «Я включил CSP — всё ок». CSP не работает, если вы используете ExecuteScriptAsync() с динамическим кодом. CSP блокирует только встроенные скрипты, но не код, который вы запускаете из C#.
  • «Я не использую PostMessage». Но вы используете ExecuteScriptAsync("alert('xss')") — это тоже способ выполнить код. И это опасно.
  • «Я загружаю только HTTPS». Но сертификат не проверяется. Злоумышленник может подменить DNS и отдать фейковый сайт с валидным сертификатом Let’s Encrypt.
  • «Я использую WebView2 1.0.1150». Эта версия уязвима к CVE-2022-41080. Обновите до 1.0.2045+.
  • «Я не вижу уязвимостей в тестах». Атаки через WebView2 часто требуют специфичных условий: определённая версия ОС, установленные обновления, конфигурация сети. Тесты на вашей машине — не гарантия безопасности.

Как лучше сделать: практические рекомендации

Вот чек-лист, который я использую в каждом проекте с WebView2:

  1. Отключите всё, что не нужно: DevTools, WebMessage, HostObjects, Script.
  2. Загружайте только локальные файлы или HTTPS-сайты с проверенным доменом. Не используйте пользовательские URL.
  3. Настройте строгий CSP — блокируйте всё, кроме необходимого.
  4. Проверяйте хеш файлов, если используете локальные HTML-шаблоны.
  5. Обновляйте WebView2 через онлайн-runtime — не статически.
  6. Всегда валидируйте входящие сообщения через PostWebMessageAsJson(). Не доверяйте ни одному полю.
  7. Не используйте WebView2 для отображения пользовательского HTML. Используйте санитайзеры и рендереры без браузера.
  8. Проверяйте версию WebView2 при запуске. Если ниже 1.0.2045 — покажите предупреждение и предложите обновить.
  9. Логируйте все попытки загрузки внешних ресурсов. Это поможет обнаружить атаку в реальном времени.

Что делать в зависимости от ситуации

Если вы разрабатываете:

  • Корпоративное приложение с внутренними сервисами — используйте только HTTPS с проверкой сертификата, отключите JavaScript, загружайте только с внутреннего домена. Обновляйте WebView2 через GPO.
  • Приложение для клиентов с загрузкой PDF/документов — не используйте WebView2 для отображения. Используйте PDF.js в изолированном окне или сторонний компонент.
  • Приложение с пользовательскими шаблонами — не используйте WebView2 вообще. Сделайте редактор на базе текстового контрола + санитизацию HTML через AngleSharp. Или используйте Markdown.
  • Приложение, которое подключается к API — используйте HTTPS, pinning сертификата, проверяйте структуру ответа, не вставляйте ответы в WebView2 без фильтрации.

Если вы не уверены — выбирайте самый консервативный вариант: локальный HTML, отключённый JS, только статический контент. Это безопаснее, чем любая «умная» динамика.

Итог: что делать прямо сейчас

Вы не должны ждать, пока произойдёт атака. Делайте это сейчас.

Откройте свой проект. Найдите все места, где используется webView.CoreWebView2.Navigate(). Проверьте:

  • Загружается ли URL из пользовательского ввода? → Исправьте.
  • Используется ли ExecuteScriptAsync() с динамическими строками? → Удалите или строго валидируйте.
  • Включены ли DevTools, WebMessage, HostObjects? → Отключите.
  • Есть ли CSP? → Добавьте.
  • Какая версия WebView2? → Обновите до 1.0.2045 или выше.

Если вы не можете сразу всё исправить — начните с двух шагов: отключите AreHostObjectsAllowed и AreDefaultScriptDialogsEnabled. Это уже снизит риск на 80%.

WebView2 — мощный инструмент. Но он не «безопасен по умолчанию». Без вашей защиты он — дверь в систему. С вашей — он просто красивый интерфейс.

Не откладывайте. Проверьте свой код сегодня. Потому что завтра атака может быть уже здесь.

Информация в этой статье носит ознакомительный характер. Реальная безопасность приложения требует тестирования на уязвимости, аудита кода и консультации с экспертом по информационной безопасности.

Оцените статью
PEFile — Безопасность и технологии простым языком