Certificate Pinning: що це таке, механізм і способи фіксації

Автор: IT Sectr Опубліковано: 2026-03-09 Час читання: 8 хв

Certificate Pinning — механізм фіксації сертифіката або відкритого ключа сервера, при якому додаток використовує заздалегідь відомий відбиток для перевірки HTTPS-з'єднання. На відміну від стандартного ланцюжка довіри через CA, pinning гарантує, що навіть скомпрометований центр сертифікації не зможе видати підроблений сертифікат для вашого домену. Згідно з OWASP MSTG (2025), Certificate Pinning входить до списку обов'язкових контролів для додатків рівня захисту L2. Реалізація включає зберігання хешів сертифікатів у коді та перевірку при кожному запиті.

Головне

  • Certificate Pinning — техніка, при якій додаток довіряє тільки сертифікату із заздалегідь відомим відбитком, ігноруючи весь ланцюжок CA
  • Public Key Pinning — альтернатива, що фіксує тільки відкритий ключ, що спрощує ротацію при зміні сертифіката
  • HPKP (HTTP Public Key Pinning) — застарілий стандарт на рівні HTTP-заголовків, не рекомендований для нових проектів
  • Backup pins — резервні відбитки, що забезпечують безперервність з'єднання при зміні або закінченні терміну дії основного сертифіката
  • Реалізація на iOS через SecTrustEvaluate, на Android через CertificatePinner в OkHttp або TrustManager

Що таке Certificate Pinning?

Certificate Pinning — це техніка безпеки, при якій додаток зберігає відбиток (fingerprint) довіреного сертифіката і використовує його як єдиний критерій для встановлення HTTPS-з'єднання. У стандартній моделі TLS клієнт перевіряє, що сертифікат сервера підписаний довіреним кореневим CA — будь-яким із сотень попередньо встановлених у системі центрів. Certificate Pinning замінює цей ланцюжок на пряму перевірку: сертифікат повинен збігатися зі збереженим зразком або містити очікуваний відкритий ключ.

Проблема стандартної моделі стала очевидною після інцидентів з компрометацією CA — DigiNotar (2011), Comodo (2011), TrustCor (2022). Якщо CA випускає підроблений сертифікат для вашого домену, браузер або додаток приймає його як валідний. Certificate Pinning запобігає цій атаці: навіть ідеально підписаний підроблений сертифікат буде відхилено, оскільки його відбиток не збігається із зафіксованим у додатку.

Термін pinning походить від pin — «штифт» або «фіксатор»: розробник фіксує довірений сертифікат, і будь-яке відхилення від нього блокує з'єднання. За даними дослідження Mitre CWE-295, improper certificate validation залишається однією з top-10 найбільш небезпечних помилок безпеки в мобільних додатках, і Certificate Pinning є прямим методом її запобігання.

Історія та еволюція Certificate Pinning

Спочатку Certificate Pinning використовувався в браузерах через механізм HPKP (HTTP Public Key Pinning), стандартизований у RFC 7469. Розробник надсилав HTTP-заголовок Public-Key-Pins з хешами очікуваних ключів, і браузер запам'ятовував їх на вказаний термін. Однак HPKP виявився небезпечним: одна помилка в конфігурації могла заблокувати сайт на місяці. У 2018 році Chrome припинив підтримку HPKP, і зараз стандартом стала програмна реалізація на стороні клієнта — всередині мобільного додатка або розширення браузера.

Як працює Certificate Pinning?

Процес Certificate Pinning включає три ключові етапи: обчислення відбитка, перевірка при з'єднанні та обробка помилки. На етапі підготовки розробник отримує SHA-256 хеш сертифіката або відкритого ключа продакшен-сервера. Для GDPR- та PCI DSS-сумісних додатків також потрібно зафіксувати відбитки проміжних CA в ланцюжку.

При кожному HTTPS-запиті додаток перехоплює callback аутентифікації TLS, витягує сертифікат сервера і обчислює його SHA-256 хеш. Цей хеш порівнюється зі збереженим списком довірених відбитків. Якщо збіг знайдено — з'єднання продовжується. Якщо ні — додаток повинен розірвати з'єднання і повідомити про помилку, не розкриваючи деталей реалізації зловмиснику.

kotlin
fun validateCertificate(certificate: X509Certificate,
    expectedHash: String): Boolean {
    val digest = MessageDigest.getInstance("SHA-256")
    val hash = Base64.encodeToString(
        digest.digest(certificate.publicKey.getEncoded()),
        Base64.DEFAULT
    ).trim()
    return hash == expectedHash
}

Функція приймає об'єкт X509Certificate від сервера та очікуваний хеш. Спочатку витягується відкритий ключ сертифіката, обчислюється SHA-256 хеш і кодується в Base64. Результат порівнюється з очікуваним відбитком. У продакшені варто додати перевірку по масиву з 2–3 відбитків для підтримки ротації.

Certificate Pinning vs Public Key Pinning

При реалізації pinning потрібно вибрати, який саме криптографічний об'єкт фіксувати. Certificate Pinning прив'язується до самого сертифіката X.509 — його серійного номеру, терміну дії та всього ланцюжка. Public Key Pinning фіксує тільки відкритий ключ всередині сертифіката, ігноруючи інші поля. Вибір суттєво впливає на операційні витрати.

КритерійCertificate PinningPublic Key Pinning
Об'єкт фіксаціїСертифікат X.509 цілкомВідкритий ключ RSA/ECDSA
РотаціяВимагає оновлення при кожному перевипускуНе змінюється при зміні сертифіката з тим же ключем
БезпекаМаксимально точна прив'язкаМенш чутливий до деталей
ГнучкістьНизька — сертифікати змінюються кожен 1–2 рокиВисока — ключі можуть жити 5–10 років
РекомендаціяДля критичних систем з контрольованими оновленнямиДля більшості мобільних додатків та API

Public Key Pinning — найкращий вибір для більшості проектів. Відкриті ключі серверів зазвичай залишаються незмінними при перевипуску сертифіката — компанія просто підписує старий ключ новим сертифікатом. Це означає, що додаток не потребує оновлення після зміни сертифіката, якщо ключова пара не змінювалася. Certificate Pinning ж рекомендований для сценаріїв, де розробник повністю контролює і сервер, і клієнтський код, наприклад, у корпоративних додатках з жорстким циклом оновлення.

Trust On First Use (TOFU)

TOFU — стратегія, при якій Certificate Pinning не налаштовується заздалегідь, а запам'ятовує сертифікат при першому з'єднанні з сервером. Цей підхід зручний для додатків, які не знають заздалегідь, до якого сервера будуть підключатися. Недолік — вразливість при першій атаці: якщо перше з'єднання перехоплено, підроблений сертифікат буде прийнято як довірений. TOFU застосовується в SSH-з'єднаннях і деяких P2P-протоколах.

Реалізація на iOS та Android

На обох платформах Certificate Pinning реалізується через перехоплення TLS-з'єднання на рівні мережевого стека. На iOS використовується делегат URLSession або Alamofire ServerTrustManager. На Android найкращий спосіб — OkHttp CertificatePinner, який вбудований у популярні HTTP-клієнти і підтримує конфігурацію кількох відбитків для кожного домену.

swift
func validate(serverTrust: SecTrust,
    pinnedHash: String) -> Bool {
    guard let certificates = SecTrustCopyCertificateChain(serverTrust)
        as? [SecCertificate] else { return false }

    for certificate in certificates {
        let data = SecCertificateCopyData(certificate)
        var hash = Data(repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
        data.withUnsafeBytes {
            CC_SHA256($0.baseAddress,
                CC_LONG(data.count), &hash)
        }
        if hash.base64EncodedString() == pinnedHash {
            return true
        }
    }
    return false
}

У Swift-функції з serverTrust витягується ланцюжок сертифікатів, для кожного обчислюється SHA-256 хеш, і результат порівнюється з очікуваним. Прохід по всіх сертифікатах у ланцюжку дозволяє реалізувати pinning на рівні проміжного CA — якщо проміжний сертифікат збігається, з'єднання приймається. Це дає гнучкість при ротації leaf-сертифікатів.

TrustManager для Android (кастомний)

Якщо додаток не використовує OkHttp, Certificate Pinning можна реалізувати через кастомний X509TrustManager. Цей метод вимагає більше коду, але дає повний контроль над процесом перевірки. TrustManager перевизначає метод checkServerTrusted, де розробник вручну перевіряє сертифікати сервера і приймає рішення про довіру. Рекомендується тільки для специфічних сценаріїв, де бібліотека OkHttp недоступна.

Помилки при впровадженні Certificate Pinning

Найпоширеніша помилка — відсутність backup pins. Розробник закладає один відбиток сертифіката, і при його закінченні користувачі масово втрачають з'єднання. Мінімально допустима конфігурація — два відбитки: поточний сертифікат і резервний. Оптимально — три: поточний, резервний і відбиток кореневого CA як fallback.

Друга помилка — зберігання pins у відкритому вигляді в коді. Зловмисник з доступом до APK або IPA може легко витягти відбитки і підмінити їх. Рекомендується обфускація хешів: розбити рядок на частини, зберігати в ресурсах з шифруванням або обчислювати через runtime. Для Android ефективний ProGuard з обфускацією рядкових констант.

Третя помилка — піннінг на рівні development-сертифіката. Сертифікати розробки та продакшену зазвичай різні, але розробники часто забувають переключити pins при збірці релізу. Результат — продакшен-додаток не може з'єднатися з сервером. Рішення — роздільна конфігурація pins для debug та release через BuildConfig або flavour-специфічні ресурси.

  • Ignoring certificate chain — перевірка тільки leaf-сертифіката без врахування проміжних CA, що ламає з'єднання при ротації
  • Hardcoded dates — жорстко зашиті дати закінчення сертифікатів, які не змінюються після оновлення
  • No monitoring — відсутність алертів на помилки Certificate Pinning, через що проблеми виявляються тільки від користувачів
  • TOFU без валідації — використання Trust On First Use без додаткової перевірки, що дозволяє першій MITM-атаці зафіксувати підроблений сертифікат

Поширені запитання

Чим Certificate Pinning відрізняється від SSL Pinning?

SSL Pinning — загальний термін для прив'язки до SSL/TLS сертифіката. Certificate Pinning — конкретна реалізація, що фіксує сам сертифікат X.509, а не тільки відкритий ключ. Різниця в об'єкті прив'язки: сертифікат vs ключ.

Як безпечно зберігати відбитки сертифікатів у додатку?

Рекомендується зберігати хеші в ресурсах з обфускацією через ProGuard (Android) або зашифрованими через Keychain (iOS). Уникайте зберігання pins у відкритому вигляді в strings.xml або Info.plist без шифрування.

Як часто потрібно міняти pinned відбитки?

При кожній зміні сертифіката на сервері. Рекомендується додавати новий відбиток як backup pin за 3–6 місяців до закінчення поточного, а після ротації видаляти старий. Мінімум один backup pin обов'язковий.

Чи можна вимкнути Certificate Pinning для налагодження?

Так, через умовну компіляцію: в debug-збірці pinning вимкнено, в release — увімкнено. Використовуйте BuildConfig.DEBUG на Android або #if DEBUG на iOS для перемикання. Ніколи не робіть це через runtime-флаг, доступний користувачу.

Що робити, якщо сертифікат скомпрометовано?

Негайно випустити оновлення додатка з новими відбитками та опублікувати його в сторах. Використовувати механізм форсованого оновлення. Якщо backup pins включали відбиток резервного CA, тимчасово можна переключитися на інший домен з іншим сертифікатом.

Підсумки

  • Certificate Pinning — фіксація довіреного сертифіката або його відкритого ключа для захисту від MITM-атак через підроблені CA
  • Два підходи — certificate pinning (строгий, до сертифіката) і public key pinning (гнучкий, до відкритого ключа)
  • Backup pins обов'язкові — мінімум 2 відбитки для забезпечення безперервності при ротації сертифікатів
  • OkHttp CertificatePinner — стандартний спосіб реалізації на Android з підтримкою кількох pins
  • URLSessionDelegate — основний спосіб на iOS з ручною перевіркою SecTrust та SHA-256 хешів
  • Помилки — відсутність backup pins, зберігання без обфускації, плутанина debug/release конфігурацій
  • Рекомендація — використовувати public key pinning для більшості проектів і Certificate Pinning тільки для критичних систем

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також