这是一个似乎遍布各地的问题,但到目前为止,我还没有找到明确的答案。
我的任务是为我的公司编写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"并且从不显示任何内容。
答案 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,但它实际上解决了我的问题。