Когда мы, разработчики, работаем над разработкой любого вида программного обеспечения, мы не можем забывать о безопасности 🔐 . Минимальная мера безопасности, которую мы должны использовать, – это HTTPS в качестве протокола для обмена информацией между клиентом (в данном случае приложением для Android/iOS) и сервером, за которым следует обновленный криптографический протокол, такой как TLS 1.2 (SSL 3.0 уязвим!) Вы можете подумать, что достаточно использовать HTTPS, но в некоторых случаях, таких как банковские приложения, где конфиденциальные данные могут передаваться между нашим клиентом и нашим сервером, это может быть рискованно. По умолчанию при установлении соединения TLS клиент проверяет две вещи:
- Сертификат сервера соответствует запрошенному имени хоста.
- Сертификат сервера имеет цепочку достоверности, ведущую к доверенному корневому сертификату.
Чего он не делает, так это проверяет, является ли сертификат тем конкретным сертификатом, который, как вы знаете, использует ваш сервер, и это возможная уязвимость в системе безопасности: если клиент скомпрометирован и установлен небезопасный сертификат, кто-то может совершить атаку “человек посередине”.
Решением этой проблемы является закрепление сертификата: хранение сертификата на нашем клиенте, чтобы гарантировать, что любой сделанный SSL-запрос соответствует тому, который есть у нашего сервера. Позвольте мне объяснить вам, как это сделать как в приложениях для Android, так и в приложениях для iOS.
Андроид
OkHttp lib предоставляет класс CertificatePinner для добавления в экземпляр OkHttpClient. Самый простой способ закрепить хост – это включить закрепление с поврежденной конфигурацией и прочитать ожидаемую конфигурацию при сбое соединения.
CertificatePinner certificatePinner = new CertificatePinner.Builder() .add("mydomain.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") .build(); OkHttpClient client = OkHttpClient.Builder() .certificatePinner(certificatePinner) .build();
После выполнения запроса вы увидите это сообщение на консоли:
javax.net.ssl.SSLPeerUnverifiedException: Certificate pinning failure! Peer certificate chain: sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=: CN=mydomain.com, OU=PositiveSSL sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=: CN=COMODO RSA Secure Server CA sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=: CN=COMODO RSA Certification Authority sha256/lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=: CN=AddTrust External CA Root Pinned certificates for mydomain.com: sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= at okhttp3.CertificatePinner.check(CertificatePinner.java) at okhttp3.Connection.upgradeToTls(Connection.java) at okhttp3.Connection.connect(Connection.java) at okhttp3.Connection.connectAndSetOwner(Connection.java)
Исключение предоставит вам хэши открытого ключа сертификата сервера. Вставьте их в Certificatepinner и готово! ✔
CertificatePinner certificatePinner = new CertificatePinner.Builder() .add("mydomain.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=") .add("mydomain.com", "sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=") .add("mydomain.com", "sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=") .add("mydomain.com", "sha256/lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=") .build();
iOS
Решение для iOS не так просто, потому что вам нужно сохранить сам сертификат внутри вашего приложения. В моем случае я использовал Alamofire в качестве библиотеки HTTP-клиента для Swift. Во-первых, вам нужно получить сертификат сервера в .der отформатируйте и добавьте его в свой проект iOS.
openssl s_client -showcerts -servername mydomain.com -connect mydomain.com:443 mydomainCert.der
А теперь давайте включим закрепление сертификата: для этого нам понадобятся объекты ServerTrustPolicy и Session Manager. Первый из них определит имя хоста и сертификаты, которые будут использоваться в процессе:
var serverTrustPolicies = [ "mydomain.com": .pinCertificates( certificates: ServerTrustPolicy.certificates(), validateCertificateChain: true, validateHost: true ), ]
ServerTrustPolicy.certificates() вернет все сохраненные сертификаты, а логические значения проверят цепочку сертификатов и имя хоста. Наконец, создайте объект SessionManager, используя эту политику доверия:
var sessionManager = SessionManager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies!))
Сделано! ✔. Просто используйте этот объект SessionManager для выполнения запроса
sessionManager.request("https://mydomain.com/api", method: .get, headers: headers)...
Обратная связь приветствуется! Надеюсь, это будет полезно ☺️
Источники
OkHttp: https://github.com/square/okhttp/wiki/HTTPS Аламофайр: Аламофайр:
Оригинал: “https://dev.to/drankolq/certificate-pinning-your-android-and-ios-apps”