SSL Pinning — техника безопасности, при которой приложение проверяет сертификат сервера по заранее известному отпечатку или сертификату, а не полагается на цепочку доверия CA. В отличие от стандартной проверки, pinning предотвращает перехват трафика через подменные корневые центры сертификации. По данным OWASP Mobile Security Testing Guide (2025), эта техника входит в топ-3 recommended controls для защиты от MITM-атак. Без pinning атакующий с подменным корневым сертификатом может расшифровать весь HTTPS-трафик приложения.
Главное
SSL Pinning — это механизм безопасности, при котором мобильное или веб-приложение запоминает доверенный сертификат или открытый ключ сервера и отклоняет любые соединения, сертификат которых не совпадает с сохранённым. В стандартной схеме HTTPS клиент проверяет сертификат через цепочку доверия до корневого CA — любой CA может подписать сертификат для любого домена. SSL Pinning устраняет это слабое место: вместо доверия сотням CA приложение доверяет только одному конкретному сертификату.
Проблема стандартной проверки в том, что любой из сотен корневых CA может выпустить валидный сертификат для вашего домена — случайно или по принуждению. Атакующий, получивший доступ к корпоративному прокси с собственным корневым сертификатом, может проводить MITM-атаку без предупреждения браузера. SSL Pinning закрывает эту уязвимость: даже если CA выпустил подменный сертификат, приложение его отклонит, так как отпечаток не совпадает с зафиксированным.
В мобильных приложениях SSL Pinning особенно важен, потому что устройства часто работают в незащищённых сетях — общественный Wi-Fi, корпоративные прокси с инспекцией трафика, заражённые точки доступа. По данным Verizon Mobile Security Index (2025), более 60% утечек данных в мобильных приложениях связаны с перехватом трафика на транспортном уровне.
Мобильные приложения передают чувствительные данные — токены аутентификации, платёжную информацию, персональные данные пользователей. Без дополнительной защиты HTTPS может быть скомпрометирован через подмену корневого сертификата на устройстве — например, после установки корпоративного профиля или вредоносного приложения. SSL Pinning гарантирует, что даже если на устройстве установлен подменный корневой CA, приложение продолжит проверять сертификат по собственному whitelist.
Процесс SSL Pinning состоит из трёх этапов: захват отпечатка, проверка при соединении и обработка ошибки. На этапе разработки инженер получает SHA-256 отпечаток сертификата сервера (openssl x509 -fingerprint -sha256) и встраивает его в код приложения или конфигурационный файл. При каждом HTTPS-запросе приложение вычисляет отпечаток полученного сертификата и сравнивает его с сохранённым — если значения не совпадают, соединение разрывается.
Первый этап — пиннинг на этапе сборки: разработчик заранее знает сертификаты сервера и встраивает их хеши. Второй этап — пиннинг при первом соединении (trust on first use, TOFU): приложение запоминает сертификат при первом запросе и использует его для проверки всех последующих. TOFU удобен для динамических сред, но уязвим при первой атаке — если первое соединение уже перехвачено, подменный сертификат будет принят как доверенный.
Критическая деталь — резервные отпечатки (backup pins). Сертификаты имеют срок действия, и при их замене приложение без обновления потеряет соединение с сервером. Инженеры закладывают 2–3 дополнительных отпечатка — например, отпечаток резервного сертификата и отпечаток корневого CA. Если основной сертификат меняется, приложение проверяет по backup pins, и соединение продолжает работать.
# Получение SHA-256 отпечатка сертификата
openssl s_client -connect example.com:443 </dev/null 2>/dev/null | \
openssl x509 -pubkey -noout | \
openssl pkey -pubin -outform der | \
openssl dgst -sha256 -binary | \
base64
Различают два основных подхода к реализации пиннинга: привязка к сертификату целиком (certificate pinning) и привязка к открытому ключу (public key pinning). Каждый подход имеет свои сильные стороны и ограничения, влияющие на безопасность и удобство сопровождения.
| Тип | Объект фиксации | Гибкость | Безопасность |
|---|---|---|---|
| Certificate Pinning | Весь сертификат X.509 | Низкая — при смене сертификата требуется обновление | Высокая — точная привязка |
| Public Key Pinning | Открытый ключ сертификата | Средняя — ключ может быть в новом сертификате | Высокая — менее чувствителен к деталям сертификата |
| Hash Pinning | SHA-256 хеш сертификата или ключа | Высокая — можно менять сертификаты без смены ключа | Средняя — зависит от стойкости хеша |
Привязка к сертификату — самый строгий метод. Приложение хранит копию доверенного сертификата или его SHA-256 отпечаток и сравнивает с сертификатом сервера при каждом HTTPS-соединении. Этот метод обеспечивает максимальную безопасность, но создаёт проблемы при ротации — сертификаты обычно действуют 1–2 года, после чего требуется принудительное обновление приложения. Рекомендуется для критичных систем с контролируемым циклом обновления.
Фиксация открытого ключа — более гибкий подход. Вместо целого сертификата приложение запоминает только открытый ключ RSA или ECDSA сервера. Ключ может оставаться неизменным при перевыпуске сертификата, если компания использует одну и ту же ключевую пару. Это снижает частоту обновлений приложения. Однако если ключ скомпрометирован, потребуется каскадная замена на всех клиентах.
На платформе Apple SSL Pinning реализуется через делегат URLSession. Разработчик создаёт класс, реализующий протокол URLSessionDelegate, и переопределяет метод didReceive challenge, где вручную проверяет сертификат сервера против сохранённых отпечатков. Альтернативный подход — использование Alamofire с ServerTrustManager, который упрощает конфигурацию.
class SSLPinningDelegate: NSObject, URLSessionDelegate {
let pinnedHash = "sha256/Wi24BE7j5qLk0iLvPq6ePEsVRqZ1yW0F6wLg="
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard let serverTrust = challenge.protectionSpace.serverTrust
else { return completionHandler(.cancelAuthenticationChallenge, nil) }
if validate(serverTrust, pinnedHash) {
completionHandler(.useCredential, URLCredential(trust: serverTrust))
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
}
В примере делегат получает запрос на аутентификацию от URLSession, извлекает serverTrust из challenge и сравнивает SHA-256 отпечаток сертификата с сохранённым. Если отпечаток совпадает — соединение продолжается, иначе challenge отклоняется. Для продакшена стоит добавить проверку нескольких backup pins и логирование ошибок для мониторинга.
Начиная с iOS 14 Apple добавила встроенную поддержку Certificate Pinning через Info.plist. Разработчик указывает доверенные сертификаты в ключе NSAppTransportSecurity с подсловарём NSPinnedDomains. Этот подход не требует написания кода, но менее гибкий — невозможно динамически менять pins или логгировать ошибки проверки.
На Android существует три основных способа реализации SSL Pinning: через CertificatePinner библиотеки OkHttp, через Network Security Config в XML и через кастомную проверку в HttpsURLConnection. OkHttp — самый популярный и рекомендуемый подход, используемый в Retrofit и других HTTP-клиентах.
val certificatePinner = CertificatePinner.Builder()
.add("api.example.com",
"sha256/Wi24BE7j5qLk0iLvPq6ePEsVRqZ1yW0F6wLg=")
.add("api.example.com",
"sha256/FiPq6ePEsVRqZ1yW0F6wLgWi24BE7j5qLk0iL=") // backup pin
.build()
val client = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build()
В конфигурации OkHttp разработчик указывает домен и один или несколько SHA-256 отпечатков. При первом отпечатке OkHttp сравнивает сертификат сервера с указанными pins. Если совпадения нет, клиент выбрасывает SSLPeerUnverifiedException. Backup pin обязателен — без него при смене сертификата API-запросы сразу начнут падать.
Android поддерживает декларативный Certificate Pinning через XML-конфигурацию начиная с API 24. Файл res/xml/network_security_config.xml содержит список доменов и их отпечатков. Этот метод удобен для статических конфигураций, но не позволяет реализовать TOFU или кастомную логику проверки с логированием аномалий.
<!-- res/xml/network_security_config.xml -->
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">api.example.com</domain>
<pin-set expiration="2027-12-31">
<pin digest="SHA-256">
Wi24BE7j5qLk0iLvPq6ePEsVRqZ1yW0F6wLg=</pin>
<pin digest="SHA-256">
FiPq6ePEsVRqZ1yW0F6wLgWi24BE7j5qLk0iL=</pin>
</pin-set>
</domain-config>
</network-security-config>
SSL Pinning значительно повышает безопасность мобильного приложения, но вводит операционные сложности. Главный плюс — защита от MITM-атак даже при компрометации корневых CA. Приложение доверяет только тем сертификатам, которые явно указаны разработчиком, а не всей инфраструктуре публичных центров сертификации. Это особенно критично для финансовых приложений, мессенджеров и-приложений с чувствительными данными.
Основной минус — сложность ротации сертификатов. Если сертификат истекает или отзывается, пользователи без обновления приложения теряют соединение. Решается через backup pins и механизм постепенного обновления: новое приложение знает старый и новый сертификаты, а после полного обновления пользователей старый pin удаляется из кода. Рекомендуется закладывать минимум 2 backup pins — один для текущего сертификата, один для будущего.
Ещё один компромисс — невозможность использовать публичные прокси для отладки трафика (Charles Proxy, Burp Suite) без отключения пиннинга. Это усложняет отладку сетевых запросов на этапе разработки. Решение — условная компиляция: в debug-сборке пиннинг отключён, в release — включён. OWASP рекомендует использовать флаг BuildConfig.DEBUG для переключения.
| Аспект | Преимущество | Недостаток |
|---|---|---|
| Безопасность | Защита от MITM через подменные CA | Сложность при компрометации ключа |
| Сопровождение | Явный контроль доверия | Ротация требует обновления приложения |
| Отладка | Гарантия соединения с правильным сервером | Блокировка отладочных прокси |
Часто задаваемые вопросы
Стандартная проверка HTTPS доверяет любому сертификату, подписанному известным корневым CA. SSL Pinning доверяет только конкретному сертификату или ключу — если CA выпустит подменный сертификат, приложение его отклонит.
Сертификаты обычно действуют 1–2 года. Рекомендуется обновлять pins за 3–6 месяцев до истечения текущего сертификата, добавляя новый отпечаток как backup pin, а после ротации удалять старый.
Да, но нужно учитывать, что CDN может менять сертификаты при переключении между edge-серверами. Рекомендуется привязываться к открытому ключу, а не к конкретному сертификату, и использовать несколько backup pins.
Соединение разрывается с ошибкой — на Android это SSLPeerUnverifiedException, на iOS challenge отклоняется с .cancelAuthenticationChallenge. Приложение должно корректно обработать эту ошибку и уведомить пользователя.
Нет, но OWASP рекомендует его для приложений, работающих с чувствительными данными: банкинг, медицина, корпоративные системы. Для простых read-only приложений стандартной HTTPS-проверки с сертификатами EV обычно достаточно.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также