Самозаверяющий сертификат ios9 и безопасность транспорта приложения
Я провел некоторое время, пытаясь заставить это работать. У меня есть API, к которому я подключаюсь и пытаюсь перейти на SSL с самозаверяющими сертификатами. У меня есть контроль над сервером и приложением.
Я создал самоподписанный сертификат в соответствии с этим:
https://kyup.com/tutorials/create-ssl-certificate-nginx/
sudo openssl genrsa -des3 -out ssl.key 2048
sudo openssl req -new -key ssl.key -out ssl.csr
sudo cp ssl.key ssl.key.orig & sudo openssl rsa -in ssl.key.orig -out ssl.key
sudo openssl x509 -req -days 365 -in ssl.csr -signkey ssl.key -out ssl.crt
Я пробовал некоторые параметры конфигурации на сервере (NGINX)
ssl on;
ssl_certificate /etc/nginx/ssl/ssl.crt;
ssl_certificate_key /etc/nginx/ssl/ssl.key;
ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
#ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
ssl_prefer_server_ciphers on;
А на стороне клиента я пробовал несколько разных вариантов с ATS:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
а также
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>test.example.com (NOT REALLY MY DOMAIN)</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
а также
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>test.example.com (NOT REALLY MY DOMAIN)</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
В зависимости от различных вариантов ATS я получаю ошибки:
An SSL error has occurred and a secure connection to the server cannot be made.
или же
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
The certificate for this server is invalid. You might be connecting to a server that is pretending to be “MYDOMAIN” which could put your confidential information at risk.
Есть идеи? Кто-нибудь еще борется с самоподписанными сертификатами?
PS Я на OS X 10.11.2 Beta, Xcode 7.1.1
2 ответа
Я разобрался в проблеме. Это не имеет ничего общего с App Transport Security. Я должен был удостовериться, что iOS доверяет сертификату, так как он не от доверенного органа.
Старый школьный способ сделать это путем переопределения NSURLRequest.allowsAnyHTTPSCertificateForHost не работает.
Так как я использую NSURLSession, вы должны сделать это с этим:
- (id) init {
self = [super init];
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
self.session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
return self;
}
- (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
completionHandler(NSURLSessionAuthChallengeUseCredential,[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}
Просто нужно добавить.cer в SecTrust
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void) {
if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
if let trust = challenge.protectionSpace.serverTrust,
let pem = Bundle.main.path(forResource: "https", ofType: "cer"),
let data = NSData(contentsOfFile: pem),
let cert = SecCertificateCreateWithData(nil, data) {
let certs = [cert]
SecTrustSetAnchorCertificates(trust, certs as CFArray)
completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: trust))
return
}
}
// Pinning failed
completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
}