使用NSURLConnection和NSURLProtectionSpace确定信任

我想问一个以前提出的问题的后续问题 。 我有创build一个NSURLRequest /连接的代码,运行它,并具有调用callback方法的身份validation。 以下是特定的代码:

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust] || [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodDefault]; } -(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { if ([challenge previousFailureCount] > 0) { [[challenge sender] cancelAuthenticationChallenge:challenge]; NSLog(@"Bad Username Or Password"); badUsernameAndPassword = YES; finished = YES; return; } if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { if (appDelegate._allowInvalidCert) { // Go ahead...trust me! [challenge.sender useCredential: [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge]; } else { TrustGenerator *tg = [[TrustGenerator alloc] init]; if ([tg getTrust:challenge.protectionSpace]) { // Go ahead...trust me! [challenge.sender useCredential: [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge]; } else { [[challenge sender] cancelAuthenticationChallenge:challenge]; } } } else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodDefault) { NSURLCredential *newCredential = [NSURLCredential credentialWithUser:_username password:_password persistence:NSURLCredentialPersistenceNone]; [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge]; } } 

我碰到的是“didReceiveAuthenticationChallenge”与“[challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]” 始终被调用,即使当我试图连接到服务器上的证书是可信的(做testing与Verisign证书)。 所以我看到的是我的应用程序总是提示最终用户信任,即使网站是可信的。 不好的业力,考虑到这是一个男人在中等发作时会发生什么,等等我真正在寻找的是这样的代码:

  if (appDelegate._allowInvalidCert) { // Go ahead...trust me! [challenge.sender useCredential: [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge]; } else if(The OS trusts the cert on the server) { [challenge.sender useCredential: [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge]; } else{... 

所以我花了几天的时间研究这个。 看起来像NSURLConnection API无法确定证书是否可信,安全框架中有一个方法可以解决这个问题。 所以这里是我提出的代码:

 -(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { if ([challenge previousFailureCount] > 0) { [[challenge sender] cancelAuthenticationChallenge:challenge]; NSLog(@"Bad Username Or Password"); badUsernameAndPassword = YES; finished = YES; return; } if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { SecTrustResultType result; //This takes the serverTrust object and checkes it against your keychain SecTrustEvaluate(challenge.protectionSpace.serverTrust, &result); if (appDelegate._allowInvalidCert) { [challenge.sender useCredential: [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge]; } //When testing this against a trusted server I got kSecTrustResultUnspecified every time. But the other two match the description of a trusted server else if(result == kSecTrustResultProceed || result == kSecTrustResultConfirm || result == kSecTrustResultUnspecified){ [challenge.sender useCredential: [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge]; } else { //Asks the user for trust TrustGenerator *tg = [[TrustGenerator alloc] init]; if ([tg getTrust:challenge.protectionSpace]) { //May need to add a method to add serverTrust to the keychain like Firefox's "Add Excpetion" [challenge.sender useCredential: [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge]; } else { [[challenge sender] cancelAuthenticationChallenge:challenge]; } } } else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodDefault) { NSURLCredential *newCredential = [NSURLCredential credentialWithUser:_username password:_password persistence:NSURLCredentialPersistenceNone]; [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge]; } } 

如果结果是kSecTrustResultConfirm ,则实际上应该询问用户是否是受信任的服务器。

上面的答案只适用于拥有CA信任证书的情况,因为在这种情况下,您正在使用Apple允许的CA证书进行validation。

如果您有自签名证书,您应该使用您自己的CA服务器证书来检查它是否有效。

我在这里find了一个很好的(有点混乱)。 它也涵盖了双重握手….

希望它有助于一些!