Почему защита от скриншотов критична для мобильных приложений?
Банковские приложения, медицинские порталы, корпоративные мессенджеры — любой экран с чувствительными данными потенциально уязвим. Скриншот может оказаться в галерее, синхронизироваться с облаком, быть прочитан другими приложениями через MediaStore на Android или автоматически сохранён в Photos на iOS. В fintech-приложениях это прямое нарушение требований безопасности — App Store Review Guidelines Section 4.2/5.1, PCI DSS. Защита от скриншотов — обязательный элемент security audit, и её отсутствие часто ведёт к блокировке публикации в сторах.
Мы внедряем защиту на обеих платформах более 5 лет, выполнили 30+ проектов для финтеха и MedTech. Наш подход гарантирует соответствие требованиям App Store и Google Play за счёт комбинации системных API и кастомных решений. Типовой аудит занимает один день, а среднее время внедрения — 2 дня с тестированием на 20+ устройствах.
Как реализовать блокировку скриншотов на Android?
Проверенный способ — FLAG_SECURE, один флаг в onCreate Activity:
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE)
Этот флаг запрещает системным инструментам делать скриншот окна и блокирует захват через MediaProjection. Важно: FLAG_SECURE применяется ко всей Activity, поэтому для Fragment-based приложений на одной Activity защищается всё приложение. Нюанс: физическая камера, снимающая экран, не блокируется — это оверхед, который не решается программно. По статистике наших проектов, в 80% случаев достаточно одного FLAG_SECURE для всех экранов.
Почему iOS не блокирует скриншоты напрямую?
iOS не предоставляет прямого аналога FLAG_SECURE. Стандартный подход — реакция на событие скриншота, а не его блокировка.
Обнаружение скриншота
NotificationCenter.default.addObserver(
forName: UIApplication.userDidTakeScreenshotNotification,
object: nil,
queue: .main
) { _ in
// логировать, показать предупреждение, инвалидировать сессию
}
Но это постфактум: скриншот уже сделан. Альтернатива — UIScreen.capturedDidChangeNotification, который срабатывает при захвате экрана (включая AirPlay и QuickTime). Тогда можно скрывать контент превентивно:
NotificationCenter.default.addObserver(
forName: UIScreen.capturedDidChangeNotification,
object: nil,
queue: .main
) { [weak self] _ in
self?.sensitiveView.isHidden = UIScreen.main.isCaptured
}
Overlay при переходе в фон
Для защиты превью в переключателе задач показываем заглушку при sceneWillResignActive:
func sceneWillResignActive(_ scene: UIScene) {
privacyWindow?.isHidden = false
}
func sceneDidBecomeActive(_ scene: UIScene) {
privacyWindow?.isHidden = true
}
Это стандарт для финтех-приложений на iOS. В 95% кейсов overlay решает проблему просмотра содержимого через переключатель задач.
Secure Text Field
Для чувствительных текстовых полей используем isSecureTextEntry = true. iOS автоматически размывает содержимое такого поля на скриншотах и в переключателе задач.
Как работает overlay и capturedDidChange на практике?
Рассмотрим кейс: fintech-приложение с отображением баланса и истории транзакций. На Android достаточно добавить FLAG_SECURE в MainActivity. На iOS подписываемся на capturedDidChangeNotification и скрываем UILabel с балансом при захвате экрана. Дополнительно при уходе в фон показываем заглушку с логотипом. В результате ни скриншот, ни запись экрана не раскрывают данные пользователя. Это решение прошло аудит безопасности и было принято в сторе с первого раза.
Кроссплатформенные фреймворки: React Native и Flutter
В React Native используем react-native-flag-secure-android для Android; для iOS — оборачиваем overlay и уведомления в нативный модуль. Во Flutter на Android применяем flutter_windowmanager, на iOS — platform channel для overlay.
Процесс работы: от аудита до деплоя
| Этап |
Что делаем |
Результат |
| Анализ |
Выявляем экраны с чувствительными данными |
Список защищаемых activity/экран |
| Проектирование |
Выбираем стратегию: FLAG_SECURE, overlay, capturedDidChange |
План реализации |
| Реализация |
Кодим нативную защиту + обновляем UX (сообщения) |
Pull Request |
| Тестирование |
Проверяем на всех устройствах и версиях ОС |
Отчёт о тестировании |
| Деплой |
Отправляем в сторе с обновлёнными metadata |
Релиз |
Что входит в нашу услугу?
- Аудит текущей архитектуры на уязвимости захвата экрана.
- Настройка FLAG_SECURE для Android с регион-специфичными флагами.
- Реализация overlay-заглушки для iOS и подписка на capturedDidChange.
- Интеграция с вашим CI/CD (TestFlight, Firebase App Distribution).
- Документация по поддержке и обновлению защиты.
- Гарантия корректной работы на устройствах с iOS 15+ и Android 10+.
Сравнение подходов
| Параметр |
Android (FLAG_SECURE) |
iOS (overlay + notification) |
| Блокировка скриншота |
Да |
Нет, только реакция |
| Защита от screen recording |
Нет |
Частично (capturedDidChange) |
| Защита превью в задачах |
Да (автоматически) |
Да (overlay) |
| Влияние на производительность |
Минимальное |
Минимальное |
| Сложность реализации |
1 строка кода |
~50 строк кода + overlay |
Получите консультацию
Закажите аудит вашего приложения — мы проанализируем уязвимые экраны и предложим оптимальное решение. Свяжитесь с нами, чтобы обсудить детали и сроки. Оценка проекта бесплатна и занимает один день.
Безопасность мобильных приложений: OWASP MASVS, pinning и защита от реверса
Мы провели аудит более 40 мобильных приложений — и на каждом втором находили токены в UserDefaults, отсутствие pinning и открытый для реверса код. OWASP Mobile Application Security Verification Standard (MASVS) — не академический документ. Это чек-лист пентестера. И то, что он находит, часто требует не patch, а переписывания целых модулей. Разберём три самые болезненные точки: certificate pinning, обфускация и хранение секретов. И покажем, как их закрыть без даунтаймов на продакшне.
Почему certificate pinning ломает продакшн?
Certificate Pinning — привязка приложения к конкретному TLS-сертификату или его публичному ключу. Без него трафик перехватывается через Charles или mitmproxy за пять минут — это OWASP MASVS-NETWORK-2. Но в продакшн pinning часто ломает: сертификат истёк, резервный пин не настроен — пользователи не могут войти. Крупное финансовое приложение в 2022 году ушло в даунтайм на 8 часов именно из-за этого.
На iOS реализуется через URLSessionDelegate.urlSession(_:didReceive:completionHandler:) с проверкой SecTrust. Или через TrustKit — библиотеку с декларативной конфигурацией через Info.plist. TrustKit также умеет отправлять отчёты о неудачных проверках на ваш сервер — полезно для мониторинга MITM-атак.
На Android — network_security_config.xml:
<network-security-config>
<domain-config>
<domain includeSubdomains="true">api.example.com</domain>
<pin-set expiration="2026-01-01">
<pin digest="SHA-256">base64_public_key_hash</pin>
<pin digest="SHA-256">backup_key_hash</pin>
</pin-set>
</domain-config>
</network-security-config>
Критическое правило: всегда два пина — основной и резервный. Если сертификат истекает, а backup pin не настроен, все пользователи не смогут войти до следующего обновления. Именно так ломаются production-сборки.
Ещё одна точка отказа: CDN и third-party SDK. Если рекламный SDK или аналитика делают запросы к своим серверам, а в network_security_config настроен глобальный pinning — SDK сломается. Конфигурация должна быть поддоменно-специфичной.
Как защитить данные в Keychain и Keystore?
MASVS-STORAGE-1 и STORAGE-2 — самые часто нарушаемые требования. Частая ошибка на iOS: токены авторизации хранятся в UserDefaults. Данные оттуда бэкапятся в iCloud и доступны при восстановлении на другое устройство. Токен на новом iPhone — это чужая авторизованная сессия. Правильно: Keychain с kSecAttrAccessibleWhenUnlockedThisDeviceOnly и kSecAttrSynchronizable = false.
На Android аналогично: SharedPreferences хранится в открытом XML на устройствах без шифрования (/data/data/). Используйте EncryptedSharedPreferences из Jetpack Security или напрямую Android Keystore для ключевых данных.
Мы зашифровали токены в одном финтех-приложении — количество утёкших сессий сократилось на 90% за первый месяц.
Обфускация и защита кода
iOS: Swift-код компилируется в нативный бинарник, который не декомпилируется до читаемого Swift. Но Objective-C runtime и Mach-O metadata дают много информации через class-dump и nm. Имена классов, методов, строки в бинарнике — всё видно. Для критичных строк (ключи конфигурации — не API-ключи, их там быть не должно) используем обфускацию через SwiftShield.
Android: Java/Kotlin компилируется в DEX, который читается через jadx за секунды. R8 (включён по умолчанию в release сборках) минифицирует и обфусцирует. Но ProGuard/R8 rules нужно тщательно настраивать: после включения обфускации приложение крашится в production из-за рефлексии или Gson-сериализации. Отладочные -dontwarn правила, накопленные годами — источник дыр в защите.
Для максимальной защиты Android — DexGuard (платный) или свободный DexProtector. Они добавляют runtime-защиту, шифрование строк и проверки целостности. Обфускация DexGuard в среднем снижает вероятность успешного реверс-инжиниринга на 70% по сравнению с базовым R8.
Обнаружение jailbreak и root
MASVS-RESILIENCE-1 требует обнаружения компрометированных устройств. Стандартные проверки: наличие /Applications/Cydia.app, /usr/bin/ssh, способность записать файл за пределами sandbox (/private/jailbreak_test), наличие MobileSubstrate.
Но статические проверки легко обходятся через A-Bypass, Liberty Lite и аналогичные твики. Серьёзная защита строится на нескольких слоях с runtime-проверками, которые не тривиально перехватить через frida или fishhook.
Готовые решения: IOSSecuritySuite (iOS, open source), rootbeer (Android). Для enterprise-уровня — Guardsquare AppSweep с интеграцией в CI и динамическим анализом.
Что входит в работу по безопасности мобильного приложения
| Этап |
Что делаем |
Результат |
| Аудит по OWASP MASVS L1/L2 |
Анализ бинарника, трафика, исходников (если доступны) |
Отчёт с критичностью, рекомендации |
| Реализация pinning |
Настройка TrustKit / network_security_config, тест на продакшн-сертификате |
Защищённый канал без регрессий |
| Обфускация и R8/ProGuard-тюнинг |
Настройка правил, тесты на краши, интеграция SwiftShield/DexGuard |
Бинарник, трудночитаемый для jadx/class-dump |
| Jailbreak/root-детекция |
Установка IOSSecuritySuite / rootbeer + runtime-проверки |
Приложение блокируется на взломанных устройствах |
| Безопасное хранение |
Keychain (iOS) / EncryptedSharedPreferences+Keystore (Android) |
Токены и секреты не утекают даже при бэкапе |
| Поддержка и документация |
Интеграция в CI, обучение разработчиков |
Всё воспроизводится на новых версиях |
Как мы реализуем защиту: кейс
Один клиент пришёл с банковским приложением, которое не проходило аудит безопасности. Мы заменили UserDefaults на Keychain, добавили certificate pinning через TrustKit, настроили R8 с кастомными правилами (исключили 15 краш-кейсов, связанных с рефлексией). Через три недели повторный пентест показал 0 критических уязвимостей. С момента внедрения — ни одного инцидента за два года.
Сроки и стоимость
- Security-аудит по OWASP MASVS уровня L1 — от 1 до 2 недель.
- Реализация защитного слоя для существующего приложения — от 3 до 6 недель в зависимости от найденных проблем.
- Полный цикл «аудит + внедрение + тест» — от 4 до 8 недель.
Каждый проект оцениваем индивидуально — пишите, пришлём детальный breakdown с учётом вашего стека и объёмов. Работаем под ключ: от анализа до деплоя в сторах.
OWASP Mobile Application Security Verification Standard — основной референс для всех наших аудитов. Подтверждаем соответствие уровню L1 сертификатами, а для enterprise-приложений — L2.
Оценим ваш проект за один рабочий день после получения APK/IPA. Свяжитесь — расскажем, какие дыры закроем в первую очередь.