Цифровая слежка в кармане: аудит 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-скорингом и разбором механизмов слежки:


Дисклеймер

Данный аудит — статический анализ 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.