Основы безопасности Android
Безопасность Android-приложения - это защита пользовательских данных, сессий и привилегированных операций с учетом того, что клиент работает на устройстве вне контроля приложения. Цель не в том, чтобы полностью исключить reverse engineering. Важно определить реалистичные границы доверия, сократить поверхность атаки, повысить стоимость взлома и оставить критичные решения системам, которые действительно могут их контролировать.
Для изучения отдельных механизмов начните с HTTPS, TLS и сертификатов, затем перейдите к OAuth 2.0, PKCE и управлению токенами и Android Keystore и безопасному хранению. Certificate Pinning рассматривайте после стандартной проверки TLS: у него есть операционные издержки, и он нужен не каждому приложению.
Модель безопасности и границы угроз
Защищаемый ресурс (asset) - это всё, чья утечка, подмена или недоступность может причинить ущерб. В Android-приложении к таким ресурсам относятся пользовательские сессии, персональные и финансовые данные, локальные файлы, бизнес-данные, API-операции и целостность транзакций, инициированных с устройства.
Основные границы доверия проходят между:
- процессом приложения и другими приложениями;
- приложением и операционной системой Android;
- устройством и сетью;
- мобильным клиентом и backend-сервисами;
- собственным кодом и сторонними SDK или сервисами.
У разных угроз разные возможности. Случайная запись данных в лог и вызов экспортированного компонента вредоносным приложением - разные проблемы. Скомпрометированная Wi-Fi-сеть может читать или изменять незащищенный трафик, а root, debugger, hooks, emulator или runtime instrumentation позволяют наблюдать за приложением изнутри. Модифицированный APK может полностью удалить клиентские проверки.
Нужные меры зависят от чувствительности данных, влияния на бизнес, регуляторных требований, мотивации атакующего, поддерживаемых устройств и допустимых операционных затрат. Приложению для чтения публичного контента и банковскому приложению не нужен одинаковый набор защит. Хорошая threat model сначала определяет защищаемые ресурсы и реалистичных атакующих, а уже затем - необходимые механизмы защиты.
Чувствительные данные
К чувствительным данным относятся не только пароли. Типичные примеры:
- access и refresh tokens, session cookies и authorization codes;
- персональные, медицинские, геолокационные и финансовые данные;
- ключи шифрования и подписи;
- кешированные ответы backend и локальные документы;
- внутренние идентификаторы, конфигурация функций, раскрытие которой создает риск для безопасности или бизнеса, и диагностические данные;
- логи, analytics events, screenshots и crash reports с пользовательским контекстом.
Не каждый идентификатор является секретом. Публичный client ID или идентификатор записи может быть открытым по замыслу, но при этом оставаться приватным, позволять связывать действия пользователя или помогать перебору ресурсов. Классифицировать данные следует по последствиям утечки или подмены, а не по названию поля.
Храните только то, что действительно нужно продукту, и только необходимое время. Данные, которые приложение не собирает и не сохраняет, не утекут из локального хранилища или backup.
Данные при передаче и при хранении
Данные при передаче (data in transit) движутся между клиентом и удаленным сервисом. HTTPS с корректной проверкой TLS защищает конфиденциальность и целостность запросов и ответов в сети, а также аутентифицирует сервер.
Данные при хранении (data at rest) находятся в файлах, базах данных, preferences, caches и backups. Для них нужна отдельная политика хранения и жизненного цикла. TLS перестает защищать ответ, как только приложение его получило и решило сохранить, залогировать, показать или передать дальше.
Данные при использовании (data in use) находятся в памяти процесса во время работы кода. Чтобы использовать зашифрованные локальные данные, их всё равно нужно где-то расшифровать. В скомпрометированном процессе инструменты runtime instrumentation могут увидеть plaintext или вызвать операцию, использующую non-exportable key. Локальное шифрование усложняет offline extraction, но не изолирует данные от атакующего внутри процесса.
Android-клиент не является доверенной средой
APK можно скачать и исследовать. Из него извлекаются resources, manifest metadata, native libraries, constants, URLs и значения BuildConfig. Obfuscation усложняет анализ и убирает понятные имена, но не является шифрованием и не превращает встроенное значение в секрет.
Android sandbox, app signing, permissions, verified boot и hardware-backed keys дают реальную защиту. Они изолируют обычные приложения и значительно усложняют многие атаки. Но клиент не становится доверенным backend: на скомпрометированном устройстве можно наблюдать или менять состояние процесса, а repackaged client может не выполнять локальные проверки.
Приложение может контролировать UX-правила локально, но backend обязан контролировать критичную авторизацию и бизнес-правила.
Например, скрытая кнопка администратора - полезное поведение UI, но не граница авторизации. Для каждой защищенной API-операции сервер должен проверить пользователя, разрешение, принадлежность ресурса и бизнес-ограничения.
Распространенные риски безопасности Android
- Hardcoded secrets: credentials, помещенные в исходный код, resources,
BuildConfig, manifest metadata или native code, можно извлечь из установленного приложения. - Чувствительные логи: request headers, tokens, персональные данные и расшифрованные payloads могут попасть в Logcat, analytics или crash reporting.
- Небезопасное хранение и backups: обычные preferences, files, database rows или неверные backup rules могут раскрыть долгоживущие credentials и кешированные данные.
- Экспортированные компоненты и небезопасные intents: activity, service, receiver или provider со слишком широким intent filter, permission или слабой validation может быть вызван другим приложением.
- Небезопасный WebView: загрузка недоверенного контента с мощными настройками или JavaScript bridge без узкой модели доверия пересекает границы приложения и web-контента.
- Cleartext-трафик или отключенная проверка TLS: HTTP, принимающий всё
TrustManagerили разрешающийHostnameVerifierубирают защиту трафика или аутентификацию сервера. - Риски зависимостей: устаревшие библиотеки и ненужные SDK увеличивают attack surface и могут собирать или раскрывать больше данных, чем ожидается.
- Избыточное хранение: старые caches, данные предыдущего account, содержимое clipboard и screenshots могут храниться дольше, чем это действительно необходимо.
Для чувствительных экранов иногда оправдан FLAG_SECURE, но он влияет на удобство и не блокирует все способы захвата. Credentials лучше не помещать в clipboard, поскольку их могут раскрыть другие поверхности системы и пользовательские сценарии.
Многоуровневая защита
Defense in depth объединяет независимые слои, чтобы отказ одного механизма не означал полный компромисс:
- backend остается источником истины для авторизации;
- TLS служит базовой защитой трафика;
- platform configuration ограничивает exported surfaces, cleartext traffic и permissions;
- шифрование с ключом из Android Keystore защищает выбранные локальные данные от простого offline extraction;
- короткоживущие credentials, rotation и revocation сокращают время риска;
- least privilege ограничивает доступ компонентов, accounts, SDK и backend;
- обновление зависимостей снижает риск известных уязвимостей;
- observability помогает обнаруживать проблемы без записи чувствительных payloads;
- release signing и разделение variants не допускают debug-поведение в production;
- tests, threat reviews и incident runbooks проверяют код и пути восстановления.
Ни один слой не делает приложение безопасным сам по себе. Набор защит должен соответствовать конкретной threat model и иметь владельцев, которые будут его поддерживать.
Чек-лист ревью безопасности
Этот список полезен при проектировании и проверке pull request. Для систем с высоким риском он не заменяет профессиональный security audit.
Данные
- Какие assets и персональные данные обрабатываются и как долго они хранятся?
- Можно ли отказаться от сбора, сохранения, screenshots, clipboard или backup?
Сеть и хранение
- Везде ли используется HTTPS, запрещен ли cleartext и сохранена ли стандартная проверка сертификатов?
- Есть ли у чувствительных сохраненных данных понятный lifecycle ключа, backup, migration и recovery?
Аутентификация и авторизация
- Проверяет ли backend каждую защищенную операцию и доступ к ресурсу?
- Имеют ли tokens короткий срок жизни, осознанное хранение, один coordinated refresh, revocation при поддержке и удаление при logout?
Поверхности Android
- Явно ли ограничены и проверены exported components, permissions, deep links, pending intents и входящие extras?
- Загружает ли WebView только ожидаемый контент с минимальным набором возможностей и без неоправданного JavaScript bridge?
Диагностика и release
- Удаляют ли logs, analytics, crash reports и network inspectors credentials и персональные данные?
- Отсутствуют ли в release debug CAs, test endpoints, debuggable flags и неконтролируемые diagnostic menus?
Поддержка и восстановление
- Актуальны и действительно ли нужны зависимости, проверены ли их data collection и exported components?
- Что произойдет после invalidation ключа, повреждения хранилища, отказа refresh, ротации сертификата, reinstall или account switch?