2015-11-23 3 views
0

Я работаю над iOS 8+ App, которое должно позволить пользователям общаться с WebService на своих серверах. Разумеется, использование HTTPS-соединения было бы оптимальным для этого, но на самом деле будет много пользователей, которые не имеют (доверенного) SSL-сертификата на своем сервере.NSURLSession - Игнорировать предупреждение сертификата SSL

Я хотел бы разрешить пользователям самостоятельно решать, хотят ли они использовать простой HTTP или HTTPS. Кроме того, HTTPS должен работать, даже если сервер имеет действующий SSL-сертификат. Так как сертификат «только» гарантирует подлинность сервера, но не имеет никакого влияния на шифрование соединения это сам, untrustes HTTPS подоконник имеет свои преимущества по сравнению с обычной HTTP:

  • Я знаю, что сертификаты были изобретены хорошая причина
  • Я знаю о рисках MITM атаки
  • Я согласен, что с помощью действительного сертификата SSL будет лучшим вариантом
  • Я все еще верю, что с помощью HTTPS без CERT должна быть вариантом для пользователей ,

Итак, как это сделать?

Сначала я работал с NSURLConnection sendAsynchronousRequest, но так как это не позволяет контролировать процесс проверки сертификата (и потому, что он устарел в iOS 9), я переключился на NSURLSession.

Я последовал Apples docs доверять своему серверу, но не имел успеха:

- (id)init { 
    ... 
    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; 
    session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]]; 
    ... 
} 


- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {  
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { 
     SecTrustRef trust = challenge.protectionSpace.serverTrust; 
     NSURLCredential *credential = [NSURLCredential credentialForTrust:trust]; 
     completionHandler(NSURLSessionAuthChallengeUseCredential, credential); 
    } else { 
     completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); 
    } 
} 

- (void)sendRequest:(NSURL *)URL { 
    NSURLRequest* request = [[NSURLRequest alloc] initWithURL:url]; 

    [[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
     if (error) { 
      // ERROR 
      --> Log error 
     } else { 
      // SUCCESS 
     } 
    }] resume]; 
} 

- (void)test { 
    // HTTP works fine 
    [self sendRequest:[NSURL URLWithString:@"http://my.test.page.xy"]]; 

    // Error with HTTPS 
    [self sendRequest:[NSURL URLWithString:@"https://my.test.page.xy"]]; 

    // Error Domain=NSURLErrorDomain 
    // Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." 
    // UserInfo={ 
    //  _kCFStreamErrorCodeKey=-9824, 
    //  NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, 
    //  NSUnderlyingError= { 
    //   Error Domain=kCFErrorDomainCFNetwork 
    //   Code=-1200 
    //   UserInfo={ 
    //    _kCFStreamPropertySSLClientCertificateState=0, 
    //    _kCFNetworkCFStreamSSLErrorOriginalValue=-9824, 
    //    _kCFStreamErrorDomainKey=3, 
    //    _kCFStreamErrorCodeKey=-9824 
    //   } 
    //  }, 
    //  NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., 
    //  NSErrorFailingURLKey=https://my.test.page.xy, 
    //  NSErrorFailingURLStringKey=https://my.test.page.xy, 
    //  _kCFStreamErrorDomainKey=3 
    // } 
} 

ли ручка я URLSession:session task:didReceiveChallenge:challenge completionHandler: или нет не имеет никакого значения. Ошибка такая же.

Итак, любая идея, как использовать HTTPS на серверах без сертификата? В соответствии с Apples docs это должно работать, не так ли?

+0

Да, потому что в сегодняшнем мире безопасность не имеет значения, не так ли? Сделать что-то подобное просто делает проблему хуже, это хорошая идея? Атакующие просто ищут слабый момент, им все равно, насколько безопасны другие части. И всегда есть оправдания для плохой безопасности. – zaph

+1

Это ваше мнение и не имеет никакого отношения к вопросу. Если у кого-то есть сервер, но нет сертификата SSL, он будет вынужден использовать простой HTTP. НЕТ аутентификации и НЕТ целостности/шифрования. Как именно это делает хуже, чем HTTPS без сертификата (нет аутентификации, но все еще шифрование)? Многие NAS-боксы могут использоваться с HTTPS, но не имеют (доверенного) сертификата. Почему в этих случаях нельзя использовать HTTPS? –

+0

Правда, я считаю, что безопасность должна быть требованием, и если она должна быть реальной. Если нет сертификата https не представляется возможным, это открытый ключ из сертификата, который используется для шифрования симметричного ключа шифрования. Если нет доверенного сертификата и нет привязки, есть только внешний вид безопасности, и это хуже, чем отсутствие безопасности, то есть пользователь доверяет то, чему не следует доверять. Атаки в наши дни довольно сложны, но довольно легко применяются атакующим. – zaph

ответ

0

Я думаю, что вы должны фактически оценить объект доверия один раз (хотя фактический результат этой оценки игнорируется).

С учетом сказанного, пожалуйста проверьте, чтобы убедиться, что это на самом деле ваш CERT, прежде чем принять его. См. Overriding SSL Chain Validation Correctly для примеров того, как это сделать.

Смежные вопросы