Приложение перехватывают через Charles Proxy или Frida — читают запросы, модифицируют ответы, изучают API. Это происходит потому, что TLS-соединение валидирует сертификат относительно системных CA, а пользователь (или пентестер) просто добавил свой CA в доверенные. За последние 5 лет мы внедрили Certificate Pinning для 30+ мобильных проектов — от финтех-стартапов до enterprise-решений. Это полностью закрывает вектор MITM-атак на нерутованных устройствах. Настраиваем pinning на iOS и Android, включая backup-пины и CI-проверки. Сроки работ — от 2 до 5 дней в зависимости от количества хостов. Хотите оценить ваш проект? Просто напишите нам.
Почему public key pinning лучше certificate pinning?
Certificate pinning — клиент хранит полный сертификат (или его SHA-256 хэш) и сравнивает с тем, что прислал сервер. Сертификат меняется при каждом renewal — раз в 1–2 года. Если забыли обновить пин до ротации, приложение перестаёт работать у всех пользователей одновременно.
Public key pinning (HPKP-стиль) — пинится хэш SubjectPublicKeyInfo. При ротации сертификата приватный ключ часто остаётся тем же, поэтому пин актуален. Это правильный выбор для продакшена. Дополнительно держите backup pin — хэш резервного ключа (может быть у вашего CA). Сравним подходы:
| Характеристика | Certificate Pinning | Public Key Pinning |
|---|---|---|
| Частота обновления клиента | Каждые 1–2 года | Раз в несколько лет |
| Риск блокировки пользователей | Высокий | Низкий |
| Сложность реализации | Низкая | Средняя |
| Гибкость при смене CA | Требует обновления | Часто не требует |
Как мы реализуем pinning: пошаговый процесс
| Этап | Описание | Длительность |
|---|---|---|
| Анализ инфраструктуры | Определяем все хосты, получаем сертификаты и публичные ключи | 1–2 часа |
| Генерация hash-ей | Вычисляем SHA-256 SPKI для каждого ключа, включая backup-пин | 30 минут |
| Реализация pinning | Встраиваем проверку в сетевой слой (TrustKit, OkHttp, Flutter) | 1–2 дня |
| Настройка CI | Шаг для проверки, что release-сборка с pinning | 1–2 часа |
| Тестирование | Проверка блокировки через proxy, работа backup-пина | 1 день |
| Документация | Процедура ротации и контакты для экстренного обновления | 1 час |
iOS: NSURLSession + TrustKit
func urlSession( _ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void ) { guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust, let serverTrust = challenge.protectionSpace.serverTrust else { completionHandler(.cancelAuthenticationChallenge, nil) return } guard let serverCert = SecTrustGetCertificateAtIndex(serverTrust, 0), let serverKey = SecCertificateCopyKey(serverCert) else { completionHandler(.cancelAuthenticationChallenge, nil) return } let serverKeyData = SecKeyCopyExternalRepresentation(serverKey, nil)! as Data let serverKeyHash = sha256(data: serverKeyData) let pinnedHashes = ["base64encodedSHA256ofSubjectPublicKeyInfo=="] if pinnedHashes.contains(serverKeyHash) { completionHandler(.useCredential, URLCredential(trust: serverTrust)) } else { completionHandler(.cancelAuthenticationChallenge, nil) } } Для проектов с несколькими хостами используйте TrustKit — конфигурируется через Info.plist, поддерживает backup pins и reporting violations.
Android: OkHttp CertificatePinner
val certificatePinner = CertificatePinner.Builder() .add("api.example.com", "sha256/AAAAAAAAA...primaryKeyHash==") .add("api.example.com", "sha256/BBBBBBBBB...backupKeyHash==") .build() val client = OkHttpClient.Builder() .certificatePinner(certificatePinner) .build() OkHttp сам вычисляет SHA-256 SubjectPublicKeyInfo. При несовпадении — SSLPeerUnverifiedException. Хэши получают через openssl:
openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \ | openssl x509 -pubkey -noout \ | openssl pkey -pubin -outform der \ | openssl dgst -sha256 -binary \ | openssl enc -base64 Для Flutter используйте http_certificate_pinning пакет или нативную обёртку через platform channels.
Какие риски при неправильной реализации?
Главная операционная боль — ротация ключей. За 30+ дней до замены сертификата нужно выпустить обновление с новым backup pin, дать пользователям обновиться, затем ротировать ключ. Если этого не сделать, приложение потеряет связь с сервером у всех клиентов. В debug-сборках pinning обычно отключают через BuildConfig.DEBUG флаг или отдельный flavor. Убедитесь, что release-сборка в CI собирается именно с pinning — иначе теряете защиту.
Типичные ошибки при реализации
- Использование только одного пина — при компрометации единственного ключа нужно экстренное обновление.
- Хранение пинов в открытом виде в бинарнике — злоумышленник может извлечь их статическим анализом. Используйте обфускацию или шифрование.
- Отсутствие fallback на сертификат — если все пины не совпадают, приложение должно блокировать соединение, а не игнорировать ошибку.
- Ротация ключей без предварительного обновления клиентов — самая частая причина массовых сбоев.
Что входит в нашу работу
- Конфигурация pinning для всех хостов приложения (iOS + Android, до 5 хостов включено).
- Backup-пин — добавляем хэш резервного ключа для безаварийной ротации.
- Интеграция в CI — настраиваем флаги для разделения debug/release-сборок.
- Документация — описание процедуры обновления пинов и контакты для экстренного релиза.
- Поддержка — в течение 30 дней после внедрения отвечаем на вопросы и помогаем с первой ротацией.
Сроки
Настройка pinning на одном хосте с backup-пинами — 2–3 дня. Для проектов с 3+ хостами — до 5 дней. Стоимость рассчитывается индивидуально, в зависимости от сложности и количества платформ.
Получите консультацию: свяжитесь с нами, и мы рассчитаем сроки под ваш проект. Напишите нам — оценим ваш проект за один день.







