Друзья, привет! Сегодня разберем важную тему — защиту сетевых запросов с помощью certificate pinning. Это обязательная защита для любого приложения, которое работает с пользовательскими данными.
⚠️ Зачем это нужно?
Основная цель — защита от атак «человек посередине» (Man-in-the-Middle). Злоумышленники могут перехватывать ваши запросы, тестировать уязвимости API и даже подменять данные. Проверить уязвимость просто: достаточно запустить Charles или Proxyman и посмотреть, проходит ли трафик вашего приложения через прокси.
🤔 Как это работает?
При HTTPS-соединении сервер предъявляет цепочку сертификатов:
🔸 Корневой сертификат (доверенный, уже есть в системе).
🔸 Промежуточный сертификат.
🔸 Листовой сертификат (конечный, именно его мы будем «пиннить»).
💎 Что пиннить?
🔸 Весь сертификат (просто, но негибко).
🔸 Отпечаток (хеш) сертификата.
🔸 Публичный ключ (самый гибкий вариант).
♣️ Практическая реализация:
1️⃣ Достаем сертификат сервера:
openssl s_client -connect example.com:443 -showcerts </dev/null 2>/dev/null | awk '/-----BEGIN CERTIFICATE-----/{i++} i==1 {print}' > leaf.pem
2️⃣ Добавляем сертификат в проект как ресурс:
Например, в папку
Certificates/example.com/leaf.der3️⃣ Реализуем проверку в 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 для безопасности приложения. Да, это добавляет сложности, но защита пользовательских данных того стоит.
➡️ Подписаться на канал
Мобильный трудоголик