Цифровая слежка в кармане: аудит 11 популярных российских Android-приложений
Привет, Хабр!
Продолжаю серию аудитов. В прошлый раз я разобрал семь яндексовских приложений — и там было на что посмотреть: буфер обмена, WebRTC-утечки, распознавание ключевых слов в аудиопотоке. На этот раз расширяю выборку и меняю фокус.
Одиннадцать приложений. Банки, госсервисы, маркетплейсы, навигация, магазин приложений. Все — из топа российского Android-рынка. Методология — статический анализ (SAST) плюс пассивный перехват logcat. Трафик не вскрывался, SSL Pinning не обходился, в Secure Folder не залезал.
237 уязвимостей суммарно (включая расширенную проверку). Шесть приложений с ключами подписи образца прошлого века. ВК с 11 трекерами и рейтингом риска 98/100. И Госключ — единственный из одиннадцати, кто делает всё правильно.
Методология: что делал и чего не делал
Инструменты: MobSF (статика, SAST), apktool, jadx, androguard, самописные парсеры для трекеров и криптографических паттернов.
Что анализировалось: DEX-байткод, манифест, нативные библиотеки, сертификаты подписи, Network Security Config. Параллельно — пассивный logcat при первом холодном запуске: какие домены контактирует приложение до того, как вы успели что-то разрешить.
Что НЕ делалось: SSL Pinning не обходился, трафик не расшифровывался, root-привилегии не использовались. Это принципиально: статика + logcat — то, что доступно без вмешательства в работу приложения.
Важная оговорка: обфускация занижает числа. Там, где jadx видит 3097 обращений к крипто-функциям, реальных уязвимостей может быть меньше — часть это дубли из-за инлайнинга. Абсолютные цифры — ориентир, не приговор.
Как считается риск слежки 0–100. Взвешенная сумма шести компонентов, веса в сумме дают 100:
Компонент | Максимум | Как считается |
|---|---|---|
Трекеры | 25 | число SDK × 3 + log10(refs+1) × 3 |
VPN-детекция | 25 | по уровню: HIGH 25 / MEDIUM 15 / LOW 7 / NONE 0 |
Скрытый сбор | 20 | доля активных категорий из 8, плюс по +2 за каждую чувствительную (звонки, SMS, микрофон, буфер, контакты) |
Fingerprinting | 15 | доля активных категорий из 6 |
Геолокация | 10 | log10(refs+1) × 4 |
Удалённое управление | 5 | log10(refs+1) × 2 |
Логарифм стоит там, где число обращений может уходить в сотни тысяч и иначе перекашивает итог. Формула детерминированная и считается из JSON-отчёта анализатора — субъективной оценки в балле нет.
Что считается «уязвимостью». Каждая пронумерованная находка в отчёте (SBER-01, VTB-16 и так далее), от информационных до критичных. Уровень присваивается по CVSS 3.1: КРИТ 8.1–9.0, ВЫС 6.5–7.9, СРЕД 4.3–5.9, НИЗ 3.1–3.9, ИНФО ниже 3. Итоговые 237 распределены так: 14 критичных, 66 высоких, 94 средних, 37 низких, 26 информационных. Так что «237 уязвимостей» не равно «237 дыр, через которые вас завтра обчистят» — больше половины это средний уровень и ниже.
Госуслуги: APK взят с зеркала RuStore, не из Google Play. Это официальный пакет ru.rostel версии 27.0.1.9810-rustore.
Рейтинг риска слежки
# | Приложение | Версия | Трекеров | Слабый ключ | VPN-детекция | Крипто-слабости | Риск |
|---|---|---|---|---|---|---|---|
1 | VK | 8.195 | 11 | RSA-1024 ✗ | HIGH | 3097 | 98.0 |
2 | Т-Банк | 8.2.3 | 6 | RSA-2048 | HIGH | 4931 | 96.6 |
3 | Сбербанк | 17.11.0 | 7 | RSA-1024 ✗ | HIGH | 705 | 96.0 |
4 | Госуслуги | 27.0.1 | 8 | RSA-1024 ✗ | HIGH | 1634 | 95.2 |
5 | Авито | 232.0 | 11 | RSA-1024 ✗ | HIGH | 875 | 94.3 |
6 | ВТБ | 20.16.0 | 5 | RSA-2048 | MEDIUM | 3988 | 89.5 |
7 | 2ГИС | 7.28.0 | 9 | RSA-4096 | MEDIUM | 1737 | 83.3 |
8 | RuStore | 1.109.1 | 8 | RSA-2048 | MEDIUM | 798 | 81.0 |
9 | Яндекс Пэй | 0.241.0 | 5 | DSA-1024 ✗ | LOW | 5139 | 77.3 |
10 | Ozon Bank | 19.33.1 | 6 | RSA-1024 ✗ | LOW | 157 | 71.6 |
11 | Госключ | 2.20.0 | 2 | RSA-2048 | NONE | 210 | 42.4 |
✗ — ключ подписи ниже 2048 бит, считается слабым по NIST SP 800-57 и Android CDD
Топ-находки
1. Слабые ключи подписи: шесть приложений живут в 2010 году
Шесть из одиннадцати приложений подписаны ключами, которые не соответствуют современным стандартам:
RSA-1024: VK, Сбербанк, Госуслуги, Авито, Ozon Bank
DSA-1024: Яндекс Пэй
NIST SP 800-57 — это рекомендация, не требование, и с 2013 года там значится нижняя граница в 2048 бит. Публично задокументированной факторизации ключа такой длины вне лабораторных условий на сегодня нет — это гипотетический риск на горизонте роста вычислительных мощностей, а не подтверждённая уязвимость. Отдельный вопрос — компрометация ключа: она не зависит от его длины и происходит не через подбор, а через утечку хранилища или процесса подписи. Тут риск для RSA-1024 и RSA-4096 одинаковый. Единственное, для чего конкретно важна длина, — устойчивость именно к подбору: 1024 бита оставляют меньше запаса на будущее, чем 2048+.
Для банковского приложения с 50+ млн пользователей — Сбербанк, я о тебе — это не «академическая угроза». RSA-2048 — минимум, RSA-4096 (как у 2ГИС) — хорошая практика.
Яндекс Пэй — отдельный случай: DSA-1024 в платёжном приложении. DSA вообще редко встречается в мобильных приложениях, а DSA-1024 — тем более.
2. Трекерная экосистема: HMS Huawei везде, VK-экосистема расширяется
HMS Huawei присутствует в 10 из 11 приложений. Единственное исключение — VK (там HMS тоже есть, 30 458 ссылок, просто доля меньше). В Госключе — 22 293 ссылки на HMS. Это государственное приложение для хранения ЭЦП.
Разберём по лидерам:
VK (11 трекеров, максимум в выборке):
VK_SDK: 2 350 342 ссылки — да, это число правильное
AppMetrica_io: 49 909
HMS_Huawei: 30 458
MailRu: 25 863
MyTracker: 7390
Firebase + Crashlytics + Facebook + RuStore
Авито (11 трекеров, равный максимум):
AppMetrica_io: 46 904
Firebase_Core: 30 382
VK_SDK: 20 668
Facebook: 17 463
HMS_Huawei: 12 988
Adjust + MyTracker + Crashlytics + RuStore
Госуслуги (8 трекеров):
HMS_Huawei: 78 571 — рекорд по этому трекеру в выборке
AppMetrica_io: 50 539
Firebase_Core: 33 937
VK_SDK: 9 088
То есть государственный портал Госуслуги передаёт аналитику в экосистему VK (9088 ссылок на VK_SDK), Яндекс (AppMetrica), Google (Firebase) и Huawei (HMS). Это не обязательно передача персональных данных — SDK может использоваться только для части функций, — но ссылки в коде означают, что SDK присутствует и инициализирован.
VK-экосистема: VK_SDK есть в Авито, Т-Банке, 2ГИС, Сбербанке, Госуслугах, Ozon Bank, RuStore. То есть VK через собственный SDK получает аналитические сигналы из семи приложений на вашем устройстве — плюс, разумеется, из своего основного.
3. VPN-детекция через WebRTC: классика жанра
Пять приложений имеют статус HIGH по VPN-детекции: VK, Т-Банк, Сбербанк, Госуслуги, Авито.
Механизм — тот же WebRTC ICE Candidate leak, который я описывал в прошлой статье. WebRTC при установке peer-to-peer соединения опрашивает все сетевые интерфейсы устройства, включая те, что находятся за VPN-туннелем. Результат: ваш реальный IP попадает в ICE Candidate list, который приложение может прочитать и отправить на сервер.
Для банковских приложений VPN-детекция — стандартная антифрод-мера. Разница в способе: проверить факт включённого VPN через TYPE_VPN — это одно, а вытащить реальный IP через WebRTC мимо туннеля — другое. Второй способ возвращает ровно тот адрес, который пользователь намеренно прятал. И вот тут я не берусь однозначно сказать, где кончается антифрод и начинается слежка.
2ГИС, RuStore и Яндекс Пэй — MEDIUM. Госключ и Ozon Bank — LOW/NONE.
Как считается уровень. Анализатор ищет в smali восемь литералов: IceCandidate, getNetworkInterfaces, tun0, ppp0, TYPE_VPN, DnsResolver, isProxy, /proc/net/tcp — и суммирует число строк-совпадений. Дальше жёсткие пороги: 15 и больше — HIGH, 6–14 — MEDIUM, 1–5 — LOW, ноль — NONE. Порог в 15 отсекает единичное упоминание внутри чужого SDK от систематического использования в нескольких местах кода. Руками уровень не правится.
4. Runtime: что происходит при первом запуске
До того как вы нажали хоть одну кнопку:
Приложение | Домены при запуске |
|---|---|
VK | firebase, crashlytics, rustore |
Т-Банк | sentry |
Сбербанк | crashlytics, firebase, metrica, rustore |
ВТБ | metrica, firebase |
Яндекс Пэй | firebase, metrica, startup.mobile.yandex, appmetrica.yandex, crashlytics |
2ГИС | firebase, crashlytics, metrica, rustore |
RuStore | metrica, rustore, firebase |
Ozon Bank | sentry, firebase |
Госключ | rustore, crashlytics, firebase |
Авито и Госуслуги — logcat был недоступен (Secure Folder или приложение не запустилось в тестовой среде).
Сразу оговорюсь, что сам по себе список доменов почти ни о чём не говорит — важно, кому они принадлежат и зачем вызываются:
firebase— Google: push-уведомления (FCM), Remote Config, аналитика. Инфраструктура, без которой push на Android просто не работает.crashlytics— Google: сбор крашей и стектрейсов. Нормальная практика, к слежке отношения не имеет.sentry— сторонний error tracking, функционально то же самое, что Crashlytics.rustore— регистрация push-токена в магазине VK. Тоже инфраструктура.metrica/appmetrica.yandex.net— AppMetrica, продуктовая аналитика Яндекса: события, сессии, идентификаторы устройства.startup.mobile.yandex— конфигурационный запрос, с которого поднимается стек яндексовых SDK.
То есть в девяти случаях из тринадцати это Firebase, Crashlytics и push, и предъявлять тут нечего. Интересен один кейс: Яндекс Пэй тянет пять доменов, из них appmetrica и startup.mobile.yandex — до того, как пользователь увидел экран с политикой конфиденциальности. Не «слежка», но аналитика, стартующая раньше согласия.
Интересно, что Госключ тоже обращается к firebase и crashlytics при запуске — это Firebase Crashlytics для мониторинга сбоев, стандартная практика. При этом трекеров у него всего два (HMS + Firebase_Core), что объясняет общий низкий риск.
Банки: сравнение четырёх игроков
Т-Банк | Сбербанк | ВТБ | Ozon Bank | |
|---|---|---|---|---|
Ключ подписи | RSA-2048 | RSA-1024 ✗ | RSA-2048 | RSA-1024 ✗ |
Трекеров | 6 | 7 | 5 | 6 |
VPN-детекция | HIGH | HIGH | MEDIUM | LOW |
Крипто-слабости | 4 931 | 705 | 3 988 | 157 |
Опасн. разрешений | 23 | 17 | 20 | 9 |
Риск слежки | 96.6 | 96.0 | 89.5 | 71.6 |
Т-Банк — 255 МБ приложение с 4931 обращением к слабым крипто-функциям. Больше всего опасных разрешений в выборке (23). HMS Huawei доминирует — 25 685 ссылок против VK_SDK (6 653). Зачем банковскому приложению настолько плотная интеграция с Huawei Mobile Services — вопрос без очевидного ответа.
Сбербанк: RSA-1024 у крупнейшего банка страны — это хочется выделить отдельно. Это не исторический артефакт в каком-то стороннем SDK, это ключ, которым подписывается APK. Для обновления достаточно сгенерировать новый ключ при следующем релизе.
ВТБ выглядит чуть лучше конкурентов по риску (89.5), при этом Amplitude присутствует в 15 ссылках — единственный банк в выборке, использующий этот американский аналитический сервис.
Ozon Bank — 71.6, лучший результат среди банков. RSA-1024 — единственный существенный минус, криптографических слабостей меньше всего в банковской четвёрке (157).
Госключ: эталон, который удивил
Давайте честно: я шёл в этот аудит с предположением, что Госключ окажется в середине рейтинга. Государственные приложения в России не особо ассоциируются с образцовой приватностью.
Результат: 42.4/100. Лучший показатель в выборке с огромным отрывом. Разрыв со вторым снизу (Ozon Bank, 71.6) — почти 30 пунктов.
Что Госключ делает правильно:
RSA-2048 — ключ подписи соответствует современным стандартам
2 трекера — только HMS_Huawei и Firebase_Core. Никакого VK_SDK, никакой рекламной атрибуции
VPN-детекция: NONE — не пытается определить, использует ли пользователь VPN
7 опасных разрешений — минимум в выборке среди нетривиальных приложений
210 крипто-слабостей — сопоставимо с Ozon Bank (157), в разы меньше, чем у банков
Контекст важен: Госключ хранит электронные цифровые подписи, работает с ЕСИА. Тут малая поверхность атаки не для галочки — чем меньше приложение умеет, тем меньше у него можно отнять.
При первом запуске — обращается к rustore, crashlytics, firebase. Никаких appmetrica, startup.mobile.yandex или VK-доменов.
Это не реклама Госключа и не сравнение с другими аспектами его безопасности (серверная сторона, PKI-инфраструктура — за пределами этого аудита). Но в рамках статики + logcat — чистый результат.
Отдельные интересные находки
RuStore (81.0): магазин приложений от VK с 360 000 ссылками на VK_SDK — в 150 раз больше, чем у следующего компонента (MailRu: 24 632). Учитывая происхождение приложения, ожидаемо — но разница на два порядка всё равно удивляет. VPN-детекция MEDIUM.
2ГИС: единственное приложение в выборке с RSA-4096 — это правильно. При этом 9 трекеров и HMS как лидер (70 823 ссылки). AppsFlyer присутствует с 16 070 ссылками — рекламная атрибуция для навигатора.
Яндекс Пэй: DSA-1024 — редкость в 2026 году. Плюс 5139 крипто-слабостей — максимум в выборке. При этом VPN-детекция LOW. Приложение явно делает ставку не на обнаружение VPN, а на другие механизмы антифрода.
Авито: 346 МБ, 11 трекеров, RSA-1024. Facebook SDK с 17 463 ссылками в российском маркетплейсе — это не блокируется на уровне DNS без потери функциональности, если Facebook SDK используется для авторизации.
Расширенная проверка: оверлеи, dropper-цепочка и разбор полёта по VK
После первичного прогона я углубился в три специфических вектора: критичные разрешения манифеста, конфигурацию NSC и SSL-bypass в smali, а также провёл дополнительную SAST-проверку хранилища, буфера обмена, фоновой геолокации и нативных библиотек. +34 новых находки, итог — 237 уязвимостей. Разберу самое интересное.
Эпидемия SYSTEM_ALERT_WINDOW в финансовых приложениях
SYSTEM_ALERT_WINDOW — разрешение на отрисовку поверх других приложений — присутствует у шести из одиннадцати: Сбербанк, ВТБ, Т-Банк, Яндекс Пэй, Авито, VK.
Приложение с этим разрешением может рисовать слой поверх чужого UI — то есть держит в руках половину механики Tapjacking/Overlay Attack. Сразу уточню маппинг, потому что в первой редакции я поставил его неправильно: CWE-1021 описывает приложение-жертву, которое не защищает свои экраны от перекрытия (filterTouchesWhenObscured). Приложению, которое само владеет оверлейным правом, корректнее ставить CWE-250 — исполнение с избыточными привилегиями.
И это не уязвимость сама по себе. Это постоянно доступная возможность, которая становится оружием, если в процесс попадает чужой код — скомпрометированный SDK, supply-chain, взломанный релиз. Ради мини-баннера держать её всё время включённой — сомнительный размен, но отдельно взятое SYSTEM_ALERT_WINDOW я бы находкой не назвал. Настораживает связка: у Сбербанка и ВТБ оно идёт вместе с правами на установку пакетов и тихое обновление (см. ниже).
Dropper-цепочка в банках: REQUEST_INSTALL_PACKAGES + UPDATE_PACKAGES_WITHOUT_USER_ACTION
Это наиболее неожиданная находка. Три банка — Сбербанк, ВТБ, Т-Банк — содержат пару:
REQUEST_INSTALL_PACKAGES— право быть установщиком сессииUPDATE_PACKAGES_WITHOUT_USER_ACTION— право устанавливать обновления без диалога подтверждения (Android 12+, API 31)
У Сбербанка и ВТБ добавлен ещё MANAGE_EXTERNAL_STORAGE — доступ ко всему внешнему хранилищу. В совокупности это полный dropper-профиль: читаем APK из Downloads, устанавливаем без уведомления пользователя.
Законное применение тут есть — обновление собственных мини-апп модулей внутри супераппа. Но для этого достаточно PackageInstaller с явным scope на собственный пакет, а не широкий REQUEST_INSTALL_PACKAGES. Комбинация трёх прав в банковском приложении без публичной документации — то, что стоило бы прямо объяснить командам безопасности этих банков.
NSC: пять приложений без явной политики TLS
NetworkSecurityConfig отсутствует у Сбербанка, Яндекс Пэй, Авито, 2ГИС и RuStore.
Что это значит и чего не значит. Не значит, что приложение доверяет пользовательским сертификатам: начиная с Android 7 (targetSdk 24) платформа user CA по умолчанию не доверяет, а у всех пяти targetSdk 36–37. Перехватить трафик, просто подсунув свой корневой сертификат, там не выйдет.
Значит другое: нет декларативного certificate pinning, нет запрета cleartext для конкретных доменов, нет per-domain политики — всё это остаётся на совести кода, и статически проверить уже нечего. Для банка я бы такую конфигурацию не назвал критичной, скорее непрозрачной: защита может быть реализована в рантайме через OkHttp CertificatePinner, а может не быть реализована вовсе, и снаружи эти два случая неразличимы.
VK: ложная тревога, которую стоит разобрать
В первой редакции статьи здесь был раздел про «единственный реальный MitM-вектор без root». Анализатор нашёл у VK в network_security_config.xml директиву <certificates src="user"/> и один TrustAllManager в smali — и я сделал вывод, что трафик снимается обычным прокси с установленным пользовательским CA.
Вывод неверный, и я благодарен читателям, которые на это указали. Разбираю, потому что случай поучительный.
Декодированный NSC из релизного APK выглядит так:
E: network-security-config E: debug-overrides E: trust-anchors E: certificates src="system" E: certificates src="user" <-- вот он E: base-config E: trust-anchors E: certificates src="system" E: certificates @res/raw/russian_trusted_root_ca E: certificates @res/raw/russian_trusted_sub_ca E: certificates @res/raw/russian_trusted_sub_ca_2024 E: certificates @res/raw/vk_self_signed E: domain-config cleartextTrafficPermitted=true E: domain 127.0.0.1, localhost E: domain mobileid.megafon.ru, idgw.mobileid.mts.ru E: domain he-mc.tele2.ru, he-mc.t2.ru, beeline.ru
<certificates src="user"/> лежит внутри <debug-overrides>, а не в <base-config>. Секция debug-overrides применяется только при android:debuggable="true"; в релизной сборке VK этот атрибут отсутствует, то есть false. Android такую секцию просто игнорирует. Перехват через пользовательский CA не работает — ровно так, как и должно быть у нормально собранного приложения.
Ошибка была в анализаторе: он искал факт наличия директивы, не разбирая, в какой секции она лежит. Это классический ложноположительный результат статики, и правило «src="user" найден → доверяет user CA» теперь проверяет родительский элемент.
Что из этого раздела остаётся правдой:
cleartextTrafficPermitted=trueприсутствует, но ограничен семью адресами: localhost и хосты Mobile ID у МегаФона, МТС, Tele2 и Билайна. Это авторизация по SIM, где оператор технически требует HTTP. Не дыра, но точка, где трафик идёт открытым.<pin-set>в конфиге нет — декларативного pinning у VK тоже не заведено.В
base-configдобавлены российские корневые CA (Минцифры) и собственный self-signed сертификат VK. Это осознанное расширение доверия за пределы системного хранилища. Практический смысл — работа при перевыпуске сертификатов внутри РФ; риск в том, что доверенных корней становится больше, чем заложено в системе.TrustAllManagerдействительно есть: обфусцированный классxsna/zyk0, исходноProxyTrustManager.kt, с пустымcheckServerTrustedи аннотацией@SuppressLint("TrustAllX509TrustManager"). Это собственный код VK, не чужая библиотека. Но он не глобальный TrustManager, а одно из звеньевCompositeTrustManager— доказать статикой, что оно включается в продакшене, я не могу. Так что честная формулировка: настораживающий класс в коде, а не подтверждённый вектор атаки.
Незащищённые exported-компоненты и утечка device_id
RuStore лидирует по открытым exported-компонентам: 22 сервиса, 3 провайдера, 5 ресиверов — без android:permission. Это значит, что любое стороннее приложение на устройстве может запустить эти компоненты напрямую через Intent.
В нескольких ContentProvider с именами, характерными для AppMetrica PreloadInfo и VK push-интеграции, присутствует паттерн доступа к device_id — потенциально эксплуатируемый без привилегий. Это «информационная» утечка уровня fingerprinting, но она работает горизонтально — между приложениями на одном устройстве.
Итог по профилю разрешений
Единственное приложение с адекватным профилем разрешений — Госключ: запрашивает ровно то, что нужно для работы с ГОСТ КЭП. Остальные — в диапазоне от «избыточный» до «агрессивный». Лидеры агрессии: Сбербанк (4 критичных разрешения), ВТБ (4), RuStore (4).
Выводы
237 уязвимостей на 11 приложений (+34 по итогам расширенной проверки). 6 слабых ключей подписи. 10 из 11 приложений с HMS Huawei. VK_SDK в 7 приложениях.
Три вещи, которые можно сделать прямо сейчас:
1. DNS-фильтрация. AdGuard Home или NextDNS. Блокирует домены трекеров без SSL Pinning и root. Не панацея, но снижает шум.
2. Рабочий профиль. Shelter / Island. Финансовые приложения с высоким риском — в изолированный профиль без доступа к контактам и основному буферу обмена.
3. Разрешения. Банки не нуждаются в фоновой геолокации. ВТБ с 20 опасными разрешениями и Т-Банк с 23 — есть что отозвать.
Ключи подписи менять сложнее: смена ключа означает переустановку приложения пользователями. Но RSA-1024 у Сбербанка и Госуслуг в 2026 году — это то, что рано или поздно придётся переделывать, и чем позже, тем дороже.
Отчёты
Полные PDF с таблицами уязвимостей, CWE-кодами, CVSS-скорингом и разбором механизмов слежки:
Пользовательский отчёт — сводка, основные выводы
Технический аудит — SAST-данные, детальные таблицы, скоринг
Дисклеймер
Данный аудит — статический анализ APK + пассивный logcat. Трафик не расшифровывался, SSL Pinning не обходился, серверная часть не анализировалась.
Обфускация занижает абсолютные числа: цифры крипто-слабостей и ссылок на трекеры — это то, что видно jadx и androguard. Реальная картина может отличаться в обе стороны.
Наличие кода трекера в APK не означает автоматической передачи данных — SDK может быть включён, но не инициализирован при определённых условиях. Logcat при первом запуске показывает то, что инициализируется в базовом сценарии.
Госуслуги — версия с зеркала RuStore (ru.rostel 27.0.1.9810-rustore), не Google Play.
Полные таблицы уязвимостей с CWE-кодами и CVSS-скорингом — в PDF-отчётах.
Методология: OWASP MASTG + MobSF + SAST.