使用 NSURLConnection 和 NSURLProtectionSpace 确定信任

Posted

技术标签:

【中文标题】使用 NSURLConnection 和 NSURLProtectionSpace 确定信任【英文标题】:Determining Trust With NSURLConnection and NSURLProtectionSpace 【发布时间】:2011-06-29 23:47:21 【问题描述】:

我想向 a previously posed question 提出后续问题。我有创建 NSURLRequest/Connection 的代码,运行它并调用用于身份验证的回调方法。具体代码如下:

- (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];
    

我遇到的是带有“[challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]”的“didReceiveAuthenticationChallenge”总是被调用,即使我正在尝试服务器上的证书连接到是受信任的(使用 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...

【问题讨论】:

好帖子!我在哪里可以找到TrustGenerator 代码? 【参考方案1】:

所以我花了几天时间研究这个。看起来虽然 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];
    

【讨论】:

+[NSURLCredential credentialForTrust:] 创建一个只为会话保留的凭据,因此它不会像 Firefox 中的附加异常一样。一旦你的应用被杀掉,你就必须重新信任它。 我知道这是一篇旧帖子,但我只是注意到 kSecTrustResultConfirm 已被弃用。【参考方案2】:

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

【讨论】:

【参考方案3】:

如果您拥有 CA 可信证书,上述答案才有效,因为在这种情况下,您使用的是苹果允许的 CA 证书进行验证。

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

我发现了一个很好的(有点混乱)here。它也涵盖了两次握手....

希望对你有所帮助!

【讨论】:

以上是关于使用 NSURLConnection 和 NSURLProtectionSpace 确定信任的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 iOS 7 的 NSURLSession 接受自签名 SSL 证书

使用NSURLConnection和NSURLProtectionSpace确定信任

使用 NSURLConnection 和 NSURLProtectionSpace 确定信任

使用 NSAutoreleasePool 和 NSURLConnection

NSMutableRequest 和 NSURLConnection 的最大超时时间

使用 NSURLConnection 和 HTTPS 发送 POST