- Как защитить приложение от атак через уязвимости в Microsoft Edge WebView2
- Что именно ломается в WebView2?
- Какие методы защиты работают на практике
- 1. Ограничьте источники контента
- 2. Изолируйте контекст
- 3. Не используйте WebView2 для отображения пользовательского контента
- 4. Обновляйте 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).
Вот как это работает:
- Установите WebView2 Runtime через официальный установщик — это не обязательно, но желательно.
- В вашем приложении используйте
CoreWebView2Environment.CreateAsync()без указания пути — тогда будет использоваться последняя установленная версия Edge. - Или — упакуйте 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:
- Отключите всё, что не нужно: DevTools, WebMessage, HostObjects, Script.
- Загружайте только локальные файлы или HTTPS-сайты с проверенным доменом. Не используйте пользовательские URL.
- Настройте строгий CSP — блокируйте всё, кроме необходимого.
- Проверяйте хеш файлов, если используете локальные HTML-шаблоны.
- Обновляйте WebView2 через онлайн-runtime — не статически.
- Всегда валидируйте входящие сообщения через
PostWebMessageAsJson(). Не доверяйте ни одному полю. - Не используйте WebView2 для отображения пользовательского HTML. Используйте санитайзеры и рендереры без браузера.
- Проверяйте версию WebView2 при запуске. Если ниже 1.0.2045 — покажите предупреждение и предложите обновить.
- Логируйте все попытки загрузки внешних ресурсов. Это поможет обнаружить атаку в реальном времени.
Что делать в зависимости от ситуации
Если вы разрабатываете:
- Корпоративное приложение с внутренними сервисами — используйте только 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 — мощный инструмент. Но он не «безопасен по умолчанию». Без вашей защиты он — дверь в систему. С вашей — он просто красивый интерфейс.
Не откладывайте. Проверьте свой код сегодня. Потому что завтра атака может быть уже здесь.
Информация в этой статье носит ознакомительный характер. Реальная безопасность приложения требует тестирования на уязвимости, аудита кода и консультации с экспертом по информационной безопасности.
