如今在移动APP开发领域,网络安全问题已经提到日程。在iOS9中,苹果引入了HTTPS请求。我分析没有那么的全面生动,我只是把我自己在做这个过程中遇到坎分享出来,我自己在以后的过程也可以及时的复习一下。写的不好,请多多包涵!
一.HTTPS
其实HTTPS从最终的数据解析的角度,与http没有任何区别,HTTPS就是将http协议数据包放到ssl/tsl层加密后,在tcp/ip层组成的IP数据报去传输,以此保证传输数据的安全;好吧,我实在是说不下去了,关于一些概念的东西,自己百度吧(太多了)。我放一张HTTPS请求的说明图给大家看一下,:
大概流程:
1. 客户端向服务器端发起连接请求,上送信息有:支持协议版本、随机数 1、加密方法、支持压缩算法;
2.服务器回应,下发信息有:确认协议版本、随机数2、确认加密方法、服务器公钥证书;
3.客户端再次上送信息:随机数3(采用公钥加密)、编码改变通知、客户端握手结束通知;
4.服务器采用随机数1、随机数2和随机数3组成会话密钥,并回应:编码改变通知、服务器握手结束通知。
以上四次握手中,完成了几件事情,第一,证书下发;第二,会话密钥;第三,确认双方参数(双方协议版本、加密方法等)。其中随机数1和随机数2是明文,随机数3是密文,之所以采用三个随机数来确定会话密钥,主要是三组随机数组成的随机数,确保了随机数的随机性,从而保证每次生成的会话密钥的安全性。
二.基础的知识了解过后,我们来一些干货。
1.创建证书
正常情况下,服务端的开发人员会有明文的证书(.pem)。我们需要把这个证书改成Xcode可以使用的证书。具体做法是通过钥匙串程序打开来,然后导出到桌面保存为.cer的文件。
2.下面就是具体代码编写
上代码前,先来了解一下系统的API的验证流程:
A: 获取需要验证的信任对象(Trust Object),在NSURLConnection来说,是从delegate方法-connection:willSendRequestForAuthenticationChallenge:回调回来的参数challenge中获取([challenge.protectionSpace serverTrust]);
B:采用系统默认方式验证Trust Object,SecTrustEvaluate会根据Trust Object的验证策略,一级一级往上,验证证书上每一级数字签名的有效性,从而评估证书的有效性;
C:通过上一步,一般安全要求下,直接验证通过,下一步使用Trust Object生成一份凭证([NSURLCredential credentialForTrust:serverTrust]),传入challenge的sender中([challenge.sender useCredential:cred forAuthenticationChallenge:challenge])处理,建立连接;
D:如果有更强的安全要求,还可以继续对Trust Object进行更严格验证,常用方式为在本地导入证书,验证Trust Object与导入证书是否匹配;
E:如果验证失败,取消此次Challenge-Response Authentication验证流程,拒绝连接请求。如果是自建证书,那么会跳过第二步,因为自建证书的根CA数字签名不在系统的信任列表中。
上代码
1.导入证书:
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"miniclouds" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
SecCertificateRef certifucate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certData));
//self.trustedCertificates 就是普通的 NSArray
self.trustedCertificates = @[CFBridgingRelease(certifucate)];
`
2.发送请求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://miniclouds.cn:8080/faces/recognition/livingrecognize"]];
request.HTTPMethod = @"POST";
NSDictionary *jsonData = @{@"session_info":@{
@"user":@"testBD",
@"password":@"123456"
}
};
NSData *data = [NSJSONSerialization dataWithJSONObject:jsonData options:NSJSONWritingPrettyPrinted error:nil];
request.HTTPBody = data;
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
[connection start];
3.代理回调
//1 代理回调 NSURLConnectionDelegate
-(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
NSLog(@"333:will send Request!!");
//1.获取trust对象
SecTrustRef trust = challenge.protectionSpace.serverTrust;
SecTrustResultType result;
//注意:这里将之前导入的证书设置成下面验证的Trust Object的anchor certificate
SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)self.trustedCertificates);
//2.SecTrustEvaluate会查找前面SecTrustSetAnchorCertificates设置的证书或者系统默认提供的证书,对trust进行验证
OSStatus status = SecTrustEvaluate(trust, &result);
if (status == errSecSuccess && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified)) {
//3.验证成功,生成NSURLCredential凭证cred,告知challenge的sender使用这个凭证来继续连接
NSURLCredential *credential = [NSURLCredential credentialForTrust:trust];
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
}else{
//4.验证失败,取消这次验证流程
[challenge.sender cancelAuthenticationChallenge:challenge];
}
}
//2 代理回调 NSURLConnectionDataDelegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSLog(@"444:didReceiveResponse");
self.receiveData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
NSLog(@"555:didReceiveData");
[self.receiveData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(@"666:didFailWithError");
NSLog(@"error%@",error.description);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(@"777:connectionDidFinishLoading");
NSString *returnString = [[NSString alloc] initWithData:self.receiveData encoding:NSUTF8StringEncoding];
NSLog(@"returnString:%@",returnString);
}
三.总结
我在做AFNetworking的时候老是报错,所以就没有写在上面。以后有机会再往上面补,如果有好的建议可以私信我。
四.参考文章
1.ios https
2.SSL/TLS协议运行机制的概述
3.图解SSL/TLS
4.iOS访问https ssl和tls双向加密