Добавить объявление

Certificate Pinning на iOS: как защитить приложение от перехвата данных

Друзья, привет! Сегодня разберем важную тему - защиту сетевых запросов с помощью certificate pinning. Это обязательная защита для любого приложения, которое работает с пользовательскими данными.

Зачем это нужно:


Основная цель - защита от атак «человек посередине» (Man-in-the-Middle). Злоумышленники могут перехватывать ваши запросы, тестировать уязвимости API и даже подменять данные. Проверить уязвимость просто: достаточно запустить Charles или Proxyman и посмотреть, проходит ли трафик вашего приложения через прокси.

Как это работает:


При HTTPS-соединении сервер предъявляет цепочку сертификатов:

  • Корневой сертификат (доверенный, уже есть в системе).

  • Промежуточный сертификат.

  • Листовой сертификат (конечный, именно его мы будем «пиннить»).

Что пиннить:


  • Весь сертификат (просто, но негибко).

  • Отпечаток (хеш) сертификата.

  • Публичный ключ (самый гибкий вариант).

Практическая реализация:



Достаем сертификат сервера:

openssl s_client -connect example.com:443 -showcerts /dev/null | awk '/-----BEGIN CERTIFICATE-----/{i++} i==1 {print}' > leaf.pem


Добавляем сертификат в проект как ресурс:

Например, в папку Certificates/example.com/leaf.der


Реализуем проверку в URLSessionDelegate:

func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge) async -> (URLSession.AuthChallengeDisposition, URLCredential?) {
let host = challenge.protectionSpace.host
let trustedCertificates = loadCertificates(for: host) // Ваш метод загрузки

guard let serverTrust = challenge.protectionSpace.serverTrust,
let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0),
trustedCertificates.contains(where: { SecCertificateEqual($0, serverCertificate) })
else {
return (.cancelAuthenticationChallenge, nil) // Блокируем соединение
}

return (.useCredential, URLCredential(trust: serverTrust))
}

Основная проблема:


Сертификаты имеют срок действия (обычно 1 год). Когда вы его обновляете, приложение с пиннингом перестанет работать! Решения:

  • Пиннить публичный ключ (если он не меняется).

  • Удаленное обновление сертификатов через CloudKit или APNS.

  • Использовать несколько сертификатов «про запас».

Советы:


  • Всегда тестируйте в режиме разработки с отключенным пиннингом.

  • Добавьте механизм аварийного отключения пиннинга.

  • Используйте готовые решения (Alamofire, TrustKit), если не хотите велосипедить.

Вывод:


Certificate pinning - это must-have для безопасности приложения. Да, это добавляет сложности, но защита пользовательских данных того стоит.
17.09.2025 14 448