是否可以在iPhone应用程序中加载带有自签名安全证书的SSL加密网站?

时间:2012-03-02 20:12:47

标签: objective-c ios ssl uiwebview

这是一个似乎遍布各地的问题,但到目前为止,我还没有找到明确的答案。

我的任务是为我的公司编写iPhone应用程序。我的公司有一个SSL-encrypted网站,上面有自签名证书。这个网站经常使用,我的雇主希望能够在iPhone上轻松访问该网站。我的应用程序的功能是提供一种存储用于访问站点的凭据的方法,当用户打开应用程序时,它会自动将存储的凭据发送到站点并跳过登录对话框直接进入站点

我已将我的应用设置为使用UIWebView并加载对该网站的请求。我已经设置了常用的身份验证方法,例如:

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {...}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {...}

当我的应用到达我告诉UIWebView加载NSURLRequest的代码部分时,它不会遇到我的任何身份验证方法。它直接跳到didFailLoadWithError,错误告诉我,我连接到的网站可能只是冒充我的网站,因为它有自签名证书。

我如何解决这个问题?我找到了一些涉及NSURLConnection方法的答案,但这些方法似乎在我到达错误之前被调用,并被迫停止加载页面。我还发现了一些涉及覆盖"无证件的答案。方法,但是当我尝试实现该解决方案时,我的Web视图永远不会到达" didFailLoadWithError"或" didFinishLoad"并且从不显示任何内容。

2 个答案:

答案 0 :(得分:2)

UIWebKit委托不会通过任何NSURLConnection委托方法转发到您的应用程序。解决此问题的一种方法是使用NSURLConnection加载页面,然后使用-loadData:MIMEType:textEncodingName:baseURL:将其推送到UIWebView。完成后,您已经验证了第一页(只要您的网站没有链接),应该保持安全。那么,我们如何验证自签名证书?

今年早些时候我不得不用OSX App来解决这个问题,一旦我弄明白我在做什么,这很简单,假设你有类似的设置。我在这里提出的解决方案实际上验证了服务器证书(虽然在我的情况下我使用的是私有CA,因此我将CA证书添加到信任根,而不是服务器证书,它应该与它一样工作)。

您需要为NSURLAuthenticationMethodServerTrust-connection:canAuthenticateAgainstProtectionSpace:方法添加-connection:didReceiveAuthenticationChallenge:的测试,以便您既可以请求并处理安全挑战。

希望这有帮助。

-(BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    // ... implement any other authentication here, such as your client side certificates or user name/password

    if ([[protectionSpace authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust])
        return YES;
    return NO;
}

-(void)connection:(NSURLConnection *)aConnection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    NSURLProtectionSpace *protectionSpace = challenge.protectionSpace;

            // implement your client side auth here for NSURLAuthenticationMethodHTTPDigest or basic or your client-side cert

    if ([[protectionSpace authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust]) {
        // install our private certificates or CAs
        NSString *myCAString = @"<string containing your CA cert>";

        SecCertificateRef certRef = SecCertificateCreateWithData ( NULL, (CFDataRef)[NSData dataFromBase64String: myCAString]);
        NSArray *anchorArray = [NSArray arrayWithObject: (NSObject*)certRef];
        SecTrustSetAnchorCertificates( challenge.protectionSpace.serverTrust, (CFArrayRef) anchorArray);

        SecTrustResultType trustResultType;
        OSStatus err=SecTrustEvaluate(challenge.protectionSpace.serverTrust, &trustResultType);

        if ((!err) && (trustResultType == kSecTrustResultProceed || trustResultType == kSecTrustResultConfirm || trustResultType == kSecTrustResultUnspecified)) {
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
        } else {
            CFArrayRef certChain=NULL;
            CSSM_TP_APPLE_EVIDENCE_INFO *statusChain;
            SecTrustGetResult( challenge.protectionSpace.serverTrust, &trustResultType, &certChain, &statusChain);
            [challenge.sender cancelAuthenticationChallenge:challenge];
        }

    } else {
        // Cancel if we don't know what it is about... this is supposed to be secure
        [challenge.sender cancelAuthenticationChallenge:challenge];
    }
}

答案 1 :(得分:1)

我已经设法通过使用RestKit框架来做你想做的事情,所以是的,我可以确认它可以做到。请参阅RestKit sources他们是如何做到的,或者只是使用RestKit。 This says how to use SSL with RestKit。在我的情况下,有一个问题 - 自签名证书必须包含某些扩展,否则我总是得到 kSecTrustResultRecoverableTrustFailure 。去看看here,答案被选为-1,但它实际上解决了我的问题。