Pull to refresh
8K+
16
16
Rating
9
Subscribers
Send message

Напишите список программ, что-бы хотели видеть в следующем аудите - сделаю.

По существу — вы правы, и не в мелочи. Признаю прямо: в тексте была логическая ошибка, а не просто резкая формулировка.

Про компрометацию vs длину ключа — вы абсолютно правы, это разные вещи. Длина ключа защищает от подбора (факторизации). Компрометация — это утечка приватного ключа из хранилища, кража у подписывающего процесса, инсайдер и так далее — способ получить ключ, который вообще не зависит от того, сколько в нём бит. RSA-4096, украденный из плохо защищённого CI/CD, компрометируется ровно так же легко, как RSA-1024. Я смешал в одном предложении два разных риска — это ошибка формулировки, а не разница мнений, и я её поправил в статье.

Про NIST — тоже справедливо. Это рекомендация, не стандарт с обязательной силой, и я подал её как строгую границу.

Про отсутствие практической факторизации RSA-1024 вне лабораторий — согласен, тут я говорил о теоретическом риске на растущих вычислительных мощностях, а не о задокументированном взломе, и это стоило явно разграничить.

Где не соглашусь — с «а так это нормальная инженерная практика для банка». Разница в контексте: вы используете RSA-1024 сознательно, зная профиль риска, ради производительности на своём масштабе, и это осознанный trade-off. У подписи APK производительность приватного ключа при подписании не имеет значения вообще — ключ используется один раз при релизе, не миллион раз в секунду на проде. Аргумент «телефон не будет рад длинному ключу» тут не работает: смартфон верифицирует подпись публичным ключом при установке, это происходит один раз, нагрузка на батарею неотличима от нуля что для RSA-1024, что для RSA-2048. Разница в производительности релевантна для TLS-хендшейков на высоконагруженном сервере — не для APK Signature Scheme.

Так что реальный аргумент за RSA-2048+ для подписи приложения — не «сегодня взломают», а «переход бесплатный по производительности и оставляет запас на будущее, зачем экономить там, где экономия ничего не даёт». Формулировка про «технический долг» в статье уже поправлена на менее драматичную версию — по существу спасибо за то, что заставили точнее развести компрометацию и длину ключа, это реальная правка, не защита лица.

Справедливо — фраза действительно штамп, из тех, что LLM вставляет не думая. Я писал текст с помощью модели и не выловил все такие места при вычитке, это на мне.

По сути вопроса — тут готов не согласиться. Стиль и достоверность фактов — разные вещи. Если находка построена на конкретном счётчике обращений в smali, конкретном классе, конкретном XML-атрибуте — она не становится ложной от того, что абзац вокруг неё звучит как канцелярит. По ходу этой ветки комментариев несколько реальных ошибок уже нашли и поправили (ложноположительный MitM-вектор у VK, неверный CWE-маппинг для SYSTEM_ALERT_WINDOW, неточная формулировка про VPN-блокировку) — и нашли их не по фразам «технический долг», а по проверке конкретных технических утверждений. Это и есть правильный способ ловить ошибки в таком материале, а не поиск AI-tells в языке.

Штампы почищу при следующей правке — они правда мешают читать. Но выводы там, где они держатся на конкретных данных из smali/манифеста/NSC, эта чистка не изменит; там, где выводы были неверны, они уже поправлены отдельно, по фактам, а не по стилю.

Разберу по пунктам, потому что вы во многом правы.

Трекеры: вы правы про VK-экосистему, но не полностью. VK SDK, Mail.ru, MyTracker технически действительно один бенефициар — это семейство SDK от VK Group, я их в статье считал по отдельности как «разные трекеры», хотя правильнее было объединить в один пункт «данные уходят в VK». Firebase/HMS/RuStore как push-инфраструктура — тоже справедливое замечание, без надёжного пуша сейчас никуда. Если пересчитать честно: инфраструктура (Firebase/HMS/RuStore) отдельно, VK-группа отдельно как один получатель, и дальше смотреть, что осталось — у большинства банков остаётся 1-3 реальных стороннихе рекламных SDK (AppsFlyer, Facebook, отдельно Яндекс AppMetrica). Это заметно меньше, чем «6-9 трекеров» звучит в лоб. Facebook у Авито и правда торчит без объяснимой причины — тут мы согласны полностью.

237 уязвимостей — тут не соглашусь. Это не придумано моделью — механическая сумма пронумерованных находок (SBER-01, VTB-16 и так далее) по 11 отчётам, я эту цифру специально перепроверял построчным подсчётом заголовков. Другой вопрос — качество этих находок неоднородное: где-то за формулировкой стоит конкретный счётчик обращений или конкретный класс в коде, а где-то вывод построен на отсутствии данных («нельзя исключить», «возможно, вызывается нативно»). Второе методологически слабее первого, и такие находки не стоило подавать с той же интонацией, что и подтверждённые. Это справедливая претензия к весу отдельных пунктов, а не к тому, что цифра высосана из пальца.

SYSTEM_ALERT_WINDOW для СБП/QR — тут вы не совсем правы, но и я неправ был. Ни в одном отчёте нет подтверждения, что это разрешение реально используется под платёжный оверлей или QR — я эту гипотезу выдвигал, но статикой она не доказывается, доказывается только сам факт наличия permission. Так что версия «это для СБП» — ровно такая же непроверенная гипотеза, как и моя версия про оверлей-атаку, только с обратным знаком. Настораживает не оверлей сам по себе, а связка SYSTEM_ALERT_WINDOW + REQUEST_INSTALL_PACKAGES + UPDATE_PACKAGES_WITHOUT_USER_ACTION у Сбера/ВТБ/Т-Банка — это уже конкретная цепочка «скачать APK → поставить без диалога», а не абстрактный риск оверлея.

Автообновление — согласен, само по себе не находка, я об этом и не писал как о находке. Проблема не в факте автообновления, а в конкретном разрешении UPDATE_PACKAGES_WITHOUT_USER_ACTION — оно добавлено в Android 12 именно для магазинов приложений (у RuStore я его отдельно оценил как низкий риск ровно по этой причине). У банка, который не магазин, это разрешение — тихое обновление без диалога согласия, и вместе с REQUEST_INSTALL_PACKAGES это и есть та самая цепочка дроппера. Если в статье это читалось как «автообновление — плохо» — плохо сформулировал, извиняюсь.

VPN-детекция — тут вы правы почти полностью. Все формулировки в отчётах про «детектирует» и «может ограничивать функциональность» — именно так, с сослагательным наклонением. Статика фиксирует только наличие кода, который умеет распознавать VPN (WebRTC ICE leak, TYPE_VPN, isProxy, чтение /proc/net/tcp) — реально ли это включено и как используется в проде, статическим анализом не проверяется в принципе. Если у вас всё через VPN работает штатно — вполне возможно, что детекция есть, а решение на её основе ничего не блокирует, либо блокирует что-то узкое (антифрод-скоринг, а не полный отказ в доступе). Я формулировал это осторожно в отчётах, но в тексте статьи местами подача жёстче, чем позволяют факты — это на мне.

Итог: переподписать ключами посерьёзнее — да, единственное, с чем вообще нет предмета для спора. Остальное — где-то вы правы и я меняю подачу, где-то моя формулировка была точнее исходной находки, чем звучит в вашем пересказе. Спасибо, что разбираете по существу, а не общими словами

Вопрос совсем не ламерский, вы нащупали ровно ту грань, где заканчивается пользовательская гигиена и начинается то, что можно поправить только на стороне разработчика. По честному:

Что реально снижается

  1. HMS вместо GMS. У вас Huawei без гуглосервисов — значит, весь канал Firebase/Google Analytics/Crashlytics физически не работает: коду просто не с кем соединиться. Это настоящее снижение, не косметика.

  2. Запрет камеры/микрофона/контактов. У Сбербанка, например, голосовой ассистент держит AudioRecord — если спотер активен в фоне, микрофон формально может писать постоянно. Без разрешения этот канал закрыт полностью, тут ваша мера бьёт точно в находку из аудита.

  3. AdGuard режет часть трекерных доменовappmetrica.yandex.net, firebase*, crashlytics, graph.facebook.com резолвятся отдельно от основного API банка, их можно блокировать без риска сломать вход и переводы.

Что не закрывается, и вот почему это важно

  1. HMS Huawei никуда не делся. Он есть в 10 из 11 приложений аудита, причём объёмы сопоставимы с Firebase или выше (у Госуслуг HMS 78 571 обращений против Firebase 33 937). У вас на Huawei-устройстве это ваш основной канал телеметрии — вы не устранили сбор, а сменили получателя с Google на Huawei. Заблокировать его DNS-фильтром сложно: он завязан на инфраструктуру, которая нужна самой системе (push, отчасти платежи).

  2. Fingerprinting не спрашивает разрешений. IMEI, Android ID, рекламный OAID, SIM-оператор, BSSID точки доступа, User-Agent — ни один из этих идентификаторов не требует камеры, микрофона или контактов. У Авито в аудите зафиксирована активность по всем 6 категориям устройства сразу, комбинация которых даёт стабильный отпечаток, не сбрасываемый даже сбросом настроек. Это работает независимо от того, что вы отключили в разрешениях.

  3. Буфер обмена читается без разрешения вообще. ClipboardManager у Сбера — 161 обращение, у Авито — 130. Система Android для этого permission не спрашивает, отключать нечего.

  4. Запрет фона откладывает отправку, а не отменяет её. Аналитические SDK (AppMetrica, HMS Analytics) складывают события в локальную базу и шлют батчем при следующем открытии приложения. Батарея живёт неделю не потому, что данные не собираются, а потому что они просто ждут своего часа в SharedPreferences/SQLite.

  5. WebRTC ICE-leak AdGuard закрывает плохо. У Авито это отдельная находка (HIGH, CVSS 7.5) — STUN-запросы раскрывают ваш реальный IP в обход VPN. Часть STUN-серверов резолвится по IP, а не по домену, и DNS-фильтр их просто не видит. Заблокировать по IP/порту AdGuard технически может, но стандартные списки трекеров под это не заточены, а грубая блокировка рискует сломать звонки внутри приложения.

  6. Банк всё равно видит вас на сервере. Сам факт транзакции, поиска, объявления виден бэкенду вне зависимости от того, что происходит на телефоне — это не про устройство, а про то, что приложение и так работает через их сервер.

Итог. То, что вы сделали, — это не «ничего не изменилось», а реальное и осмысленное снижение риска: вы закрыли самый грубый канал (Google), самый чувствительный (микрофон в фоне) и часть явных трекерных доменов. Но структурный fingerprinting и HMS как альтернативный сборщик телеметрии этим не лечатся в принципе — это вопрос к архитектуре самого приложения, а не к настройкам устройства. Если хочется зайти дальше — смотреть в сторону системного VPN с фильтрацией по IP, а не только DNS, и держать в уме, что банковское приложение видит вас на своём сервере всегда, при любых настройках.

Отвечу по пунктам, включая те, где вы правы — а их больше, чем мне бы хотелось.

Сначала главное: про VK вы поймали настоящую ошибку.

Я полез в APK и вытащил сырой NSC:

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/vk_self_signed

<certificates src="user"/> лежит внутри <debug-overrides>. Эта секция применяется только при debuggable="true"; в релизной сборке атрибут отсутствует. Android её игнорирует. Никакого MitM через установку пользовательского CA нет, находка ложноположительная.

Причина: анализатор проверял факт наличия директивы, не разбирая, в какой секции она лежит. Поправил — теперь парсится родительский элемент. Раздел в статье переписан, находка в отчёте помечена как отозванная, VK-14 понижена с ВЫС до СРЕД.

Заодно нашлось то, что стоило написать вместо этого: <pin-set> у VK нет вообще; cleartextTrafficPermitted=true включён для семи адресов (localhost и Mobile ID МегаФона, МТС, Tele2, Билайна — авторизация по SIM); в base-config добавлены российские корневые CA и собственный self-signed VK. Сам TrustAll тоже существует — обфусцированный xsna/zyk0, исходно ProxyTrustManager.kt, пустой checkServerTrusted с @SuppressLint("TrustAllX509TrustManager"), собственный код VK. Но это одно из звеньев CompositeTrustManager, и доказать статикой, что путь активен в проде, я не могу. Честная формулировка — «настораживающий класс», а не «подтверждённый вектор».

И про NSC вы правы тоже — соседние разделы действительно противоречили друг другу.

Отсутствие NSC не означает доверия к user CA: с Android 7 платформа их по умолчанию не доверяет, а у всех пяти приложений targetSdk 36–37. «Нет NSC» = нет декларативного pinning и per-domain политики, то есть снаружи неразличимо, есть ли защита в рантайме через CertificatePinner или её нет вовсе. Это непрозрачность, а не критичность. Слово «критично» из статьи убрал.

CWE-1021 — ошибка маппинга, признаю. CWE-1021 описывает жертву, которая не защищает свой UI (filterTouchesWhenObscured). Владельцу SYSTEM_ALERT_WINDOW корректнее ставить CWE-250. Исправлено.

«Почему не оправдывает» — тут я пережал. Правильно так: само по себе разрешение не уязвимость, а постоянно доступная возможность, которая становится оружием, если в процесс попадает чужой код. Настораживает не оно, а связка с REQUEST_INSTALL_PACKAGES и тихим обновлением у Сбера и ВТБ. Отдельно взятое — «ну ок». Формулировку смягчил.

Методология — справедливо, в статье её не было. Теперь есть.

VPN-детекция: восемь литералов в smali (IceCandidate, getNetworkInterfaces, tun0, ppp0, TYPE_VPN, DnsResolver, isProxy, /proc/net/tcp), считается сумма строк-совпадений, пороги жёсткие — ≥15 HIGH, 6–14 MEDIUM, 1–5 LOW, 0 NONE. Порог 15 отсекает единичное упоминание внутри чужого SDK.

Риск 0–100: шесть компонентов, веса в сумме 100 — трекеры 25, VPN 25, скрытый сбор 20, fingerprinting 15, геолокация 10, удалённое управление 5. Логарифм там, где refs уходят в сотни тысяч.

237 — сумма пронумерованных находок от ИНФО до КРИТ, распределение 14/66/94/37/26. То есть «237 дыр в проде» там не написано, и если лид читается именно так — это мой косяк подачи. Severity по CVSS 3.1, диапазоны в статье теперь приведены.

«Осознанно скрывает IP». Формулировка кривая, согласен. Смысл: проверить факт VPN через TYPE_VPN — одно, а вытащить реальный IP через WebRTC мимо туннеля — другое; второе возвращает ровно тот адрес, который прятали. Переписал.

Runtime-домены — раздел был бесполезным, тут спорить нечем. Добавил расшифровку: firebase, crashlytics, sentry, rustore — push и краш-репортинг, предъявлять нечего. Остаётся один сюжет: Яндекс Пэй поднимает appmetrica и startup.mobile.yandex до экрана с политикой конфиденциальности.

RSA-1024. Уточнил: практической атаки нет, публичный рекорд факторизации — RSA-829. Речь о депрекации по NIST SP 800-57 с 2013 года и о том, что v2/v3 меняют способ верификации, а не стойкость ключа. Технический долг, а не «завтра подделают апдейт» — подано было слишком драматично.

Про «нейронкой любую чушь». Текст писался с LLM, данные — нет: baksmali, aapt2, apksigner, свой анализатор, пассивный logcat. Без перехвата трафика, обхода пиннинга и рута. Но ваш упрёк частично попал: LLM уверенно оформила вывод из данных, которые этот вывод не выдерживали, и я это не перепроверил перед публикацией. История с VK ровно про это.

Итого принимаю: VK-вектор ложноположительный, раздел NSC противоречив, CWE-1021 не туда, домены без разбора бесполезны, формулировка про VPN небрежная, методологии не было. Шесть правок, все внесены. Спасибо, что потратили время на разбор — статья от этого стала точнее.

Вы бы хотя бы один пример привели что-ли, что в статье "чушь" и что не соответствует действительности.

А так кто да, оно с дивана конечно виднее, проще простого зайти в комментарии и безосновательно полить помоями чужие труды.

В основном статика и логи приложений

Information

Rating
542-nd
Registered
Activity

Specialization

Архитектор программного обеспечения
Ведущий