本文翻译自:How to use NSURLConnection to connect with SSL for an untrusted cert?
I have the following simple code to connect to a SSL webpage 我有以下简单的代码可以连接到SSL网页
NSMutableURLRequest *urlRequest=[NSMutableURLRequest requestWithURL:url];
[ NSURLConnection sendSynchronousRequest: urlRequest returningResponse: nil error: &error ];
Except it gives an error if the cert is a self signed one Error Domain=NSURLErrorDomain Code=-1202 UserInfo=0xd29930 "untrusted server certificate".
如果证书是自签名的,则会给出一个错误, Error Domain=NSURLErrorDomain Code=-1202 UserInfo=0xd29930 "untrusted server certificate".
Is there a way to set it to accept connections anyway (just like in a browser you can press accept) or a way to bypass it? 是否有一种方法可以将其设置为始终接受连接(就像在浏览器中可以按accept一样),还是可以绕过它?
参考:https://stackoom.com/question/3unj/如何使用NSURLConnection与SSL连接以获得不受信任的证书
If you want to keep using sendSynchronousRequest i work in this solution: 如果您想继续使用sendSynchronousRequest我可以在以下解决方案中工作:
FailCertificateDelegate *fcd=[[FailCertificateDelegate alloc] init];
NSURLConnection *c=[[NSURLConnection alloc] initWithRequest:request delegate:fcd startImmediately:NO];
[c setDelegateQueue:[[NSOperationQueue alloc] init]];
[c start];
NSData *d=[fcd getData];
you can see it here: Objective-C SSL Synchronous Connection 您可以在这里看到它: Objective-C SSL同步连接
There is a supported API for accomplishing this! 有支持的API可以完成此任务! Add something like this to your NSURLConnection
delegate: 在您的NSURLConnection
委托中添加以下内容:
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
if ([trustedHosts containsObject:challenge.protectionSpace.host])
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
Note that connection:didReceiveAuthenticationChallenge:
can send its message to challenge.sender (much) later, after presenting a dialog box to the user if necessary, etc. 请注意, connection:didReceiveAuthenticationChallenge:
可以在向用户显示对话框后(稍后)将其消息稍后发送给Challenge.sender(等等)。
To complement the accepted answer, for much better security, you could add your server certificate or your own root CA certificate to keychain( https://stackoverflow.com/a/9941559/1432048 ), however doing this alone won't make NSURLConnection authenticate your self-signed server automatically. 为了补充已接受的答案,为了提高安全性,您可以将服务器证书或您自己的根CA证书添加到钥匙串( https://stackoverflow.com/a/9941559/1432048 ),但是仅执行此操作不会使NSURLConnection有效自动验证您的自签名服务器。 You still need to add the below code to your NSURLConnection delegate, it's copied from Apple sample code AdvancedURLConnections , and you need to add two files(Credentials.h, Credentials.m) from apple sample code to your projects. 您仍然需要将以下代码添加到您的NSURLConnection委托中,它是从Apple示例代码AdvancedURLConnections复制而来,并且您需要从Apple示例代码向您的项目添加两个文件(Credentials.h,Credentials.m)。
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
// if ([trustedHosts containsObject:challenge.protectionSpace.host])
OSStatus err;
NSURLProtectionSpace * protectionSpace;
SecTrustRef trust;
SecTrustResultType trustResult;
BOOL trusted;
protectionSpace = [challenge protectionSpace];
assert(protectionSpace != nil);
trust = [protectionSpace serverTrust];
assert(trust != NULL);
err = SecTrustEvaluate(trust, &trustResult);
trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified));
// If that fails, apply our certificates as anchors and see if that helps.
//
// It's perfectly acceptable to apply all of our certificates to the SecTrust
// object, and let the SecTrust object sort out the mess. Of course, this assumes
// that the user trusts all certificates equally in all situations, which is implicit
// in our user interface; you could provide a more sophisticated user interface
// to allow the user to trust certain certificates for certain sites and so on).
if ( ! trusted ) {
err = SecTrustSetAnchorCertificates(trust, (CFArrayRef) [Credentials sharedCredentials].certificates);
if (err == noErr) {
err = SecTrustEvaluate(trust, &trustResult);
}
trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified));
}
if(trusted)
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
I can't take any credit for this, but this one I found worked really well for my needs. 我对此一无所获, 但是我发现这对于我的需求来说确实非常有效。 shouldAllowSelfSignedCert
is my BOOL
variable. shouldAllowSelfSignedCert
是我的BOOL
变量。 Just add to your NSURLConnection
delegate and you should be rockin for a quick bypass on a per connection basis. 只需添加到您的NSURLConnection
委托中,您就可以在每个连接的基础上快速绕开。
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)space {
if([[space authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if(shouldAllowSelfSignedCert) {
return YES; // Self-signed cert will be accepted
} else {
return NO; // Self-signed cert will be rejected
}
// Note: it doesn't seem to matter what you return for a proper SSL cert
// only self-signed certs
}
// If no other authentication is required, return NO for everything else
// Otherwise maybe YES for NSURLAuthenticationMethodDefault and etc.
return NO;
}
You have to use NSURLConnectionDelegate
to allow HTTPS connections and there are new callbacks with iOS8. 您必须使用NSURLConnectionDelegate
来允许HTTPS连接,并且iOS8中有新的回调。
Deprecated: 不推荐使用:
connection:canAuthenticateAgainstProtectionSpace:
connection:didCancelAuthenticationChallenge:
connection:didReceiveAuthenticationChallenge:
Instead those, you need to declare: 相反,您需要声明:
connectionShouldUseCredentialStorage:
- Sent to determine whether the URL loader should use the credential storage for authenticating the connection.connectionShouldUseCredentialStorage:
-发送以确定URL加载程序是否应使用凭据存储来验证连接。
connection:willSendRequestForAuthenticationChallenge:
- Tells the delegate that the connection will send a request for an authentication challenge.connection:willSendRequestForAuthenticationChallenge:
-告知委托人连接将发送身份验证质询的请求。
With willSendRequestForAuthenticationChallenge
you can use challenge
like you did with the deprecated methods, for example: 通过willSendRequestForAuthenticationChallenge
您可以像使用不赞成使用的方法一样使用challenge
,例如:
// Trusting and not trusting connection to host: Self-signed certificate
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];