您的位置:首页 > 理论基础 > 计算机网络

NSUrlSession NSUrlConnection https连接时证书无效的解决办法

2016-01-28 12:28 555 查看
The certificate for this server is invalid

最近公司项目需要从网络端获取部分数据,原来的接口是http的,iOS9引入的ATS机制:

所有的http请求都改成了https,采用TLS 1.2协议,目的是增强数据安全。如果不更新的话,暂时可以在Info.plist中声明,使用不安全的网络请求。首先我们在info.plist中加入以下参数:

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>


然后使用下面代码可以获取到数据:

- (NSDictionary *)postToserver:(NSURL *)address paramers:(NSDictionary *)param {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:address];
[request setHTTPMethod:@"POST"];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

NSData *data = [NSJSONSerialization dataWithJSONObject:param options:NSJSONWritingPrettyPrinted error:nil];
[request setHTTPBody:data];

NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];

__block NSDictionary *tempResult = nil;
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error == nil) {
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
tempResult = result;
}
dispatch_semaphore_signal(sem);
}];

[task resume];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
return tempResult;
}


这样就项目就支持http了,但是切换到HTTPS又有问题了。

切换到HTTPS

App Transport Security要求TLS 1.2而且它要求站点使用支持forward secrecy协议的密码。证书也要求是符合ATS规格的。因此慎重检查与你的应用交互的服务器是不是符合ATS的要求非常重要。但是有的时候小公司证书(你懂的~~~),所以我们需要在API检测证书是否有效的时候过滤掉我们的server。如果不这样操作,会出现以下错误:

Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “s3.amazonaws.com” which could put your confidential information at risk." UserInfo=0x20007030 {NSErrorFailingURLStringKey=https://s3.amazonaws.com/.../test.jpeg, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, NSErrorFailingURLKey=https://s3.amazonaws.com/.../test.jpeg, NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “s3.amazonaws.com” which could put your confidential information at risk., NSUnderlyingError=0x20014d40 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “s3.amazonaws.com” which could put your confidential information at risk.", NSURLErrorFailingURLPeerTrustErrorKey=}


解决方法

1: 使用NSURLConnection

如果你使用的是NSURLConnection,需要实现NSURLConnectionDelegate方法:

-(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust] &&
[challenge.protectionSpace.host hasSuffix:@"example.com"])
{
// 不管证书是否有效都使用
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
else
{
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
}


2: 使用NSURLSession

如果使用的是NSURLSession进行网络链接,同样需要实现NSURLSessionDelegate方法:

#pragma mark -session delegate
-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {

NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
__block NSURLCredential *credential = nil;

if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust] && [challenge.protectionSpace.host hasSuffix:@"example.com"]) {
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
if (credential) {
disposition = NSURLSessionAuthChallengeUseCredential;
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}

if (completionHandler) {
completionHandler(disposition, credential);
}
}


OK,解决问题。

注意

代码里面[challenge.protectionSpace.host hasSuffix:@”example.com”]这句判断是根据实际情况来使用,如果你想过滤掉所有的,去掉这段代码即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: