一、HTTPS
二、App Transport Security
三、iOS 中用HTTPS 注意的问题
四、使用 AFNetworking HTTPS 遇到的问题
五、问题的解决方法
六、注意服务器端 两种证书的区别(以及如何验证HTTPS服务器是否符合ATS特性中的要求)
一、HTTPS
HTTPS就是将HTTP协议数据包放到SSL/TSL层加密后,在TCP/IP层组成IP数据报去传输,以此保证传输数据的安全;而对于接收端,在SSL/TSL将接收的数据包解密之后,将数据传给HTTP协议层,就是普通的HTTP数据。HTTP和SSL/TSL都处于OSI模型的应用层。
二、App Transport Security
iOS9中新增App Transport Security(简称ATS)特性, 主要使到原来请求的时候用到的HTTP,都转向TLS1.2协议进行传输。这也意味着所有的HTTP协议都强制使用了HTTPS协议进行传输。
一般我们如果还是使用的http,不更新的话,可通过在 Info.plist 中声明,倒退回不安全的网络请求。
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
三、iOS 中用HTTPS 注意的问题
先看文档中的描述:
These are the App Transport Security requirements:
The protocol Transport Security Layer (TLS) must be at least version 1.2.
Connection ciphers are limited to those that provide forward secrecy (see the list of ciphers below.)
Certificates must use at least an SHA256 fingerprint with either a 2048 bit or greater RSA key, or a 256 bit or greater Elliptic-Curve (ECC) key.
根据原文描述,首先必须要基于TLS 1.2版本协议。再来就是连接的加密方式要提供Forward Secrecy,文档中罗列出支持的加密算法(如下表)。最后就是证书至少要使用一个SHA256的指纹与任一个2048位或者更高位的RSA密钥,或者是256位或者更高位的ECC密钥。如果不符合其中一项,请求将被中断并返回nil。
第一条就是TLS版本所需要支持的协议
第一条就是连接的加密方式需要提供“Foward Secrecy”这个东东,下面是支持Forward Secrecy的加密方式
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256` TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
这是一个满足条件的证书信息中的情况
但是也要注意证书的合法性,注意是否有效,iOS要求连接的HTTPS站点必须为CA签名过的合法证书。
注意以上不同的情况决定了AFSecurityPolicy--setAllowInvalidCertificates:
是否要验证证书的有效性。
四、使用AFNetworking HTTPS 遇到的问题(3.0.0之前)
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy];//allowInvalidCertificates 是否允许无效证书(也就是自建的证书),默认为NO//如果是需要验证自建证书,需要设置为YESsecurityPolicy.allowInvalidCertificates = YES;//validatesDomainName 是否需要验证域名,默认为YES; securityPolicy.validatesDomainName = YES; manager.securityPolicy = securityPolicy; manager.responseSerializer = [AFHTTPResponseSerializer serializer]; [manager POST:urlString parameters:dic success:finishedBlock failure:failedBlock];
但是刚开始一直不行,不能正常访问数据
第一个错是我打开 Clarles
,忘记关了
老出现`Error: Error Domain=NSURLErrorDomain Code=-1012
第二种情况,在google逛了一大圈,试着好几种方法居然不行,💢💢💢💢,特别是老看到The operation couldn’t be completed. (NSURLErrorDomain error -1012.)
,头都大了。。。
五、直到后来找到了一种解决方法...
我们可以使用以下openssl命令来获取到服务器的公开二进制证书(以google为例)
openssl s_client -connect www.google.com:443 </dev/null 2>/dev/null | openssl x509 -outform DER > https.cer
冒号中的为命令主要部分。该条命令将会在当前路径下,形成google.com站点的公开二进制证书,命名为https.cer。您可以将www.google.com 替换成您自己的站点以此来获取您自己站点的https.cer。
直接将https.cer放到资源目录中就好了,让我们可以通过pathForResource:
获取到证书,就OK了。
NSString *urlString = @"https://www.example.com/app/publicRequest";NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"https" ofType:@"cer"];NSData * certData =[NSData dataWithContentsOfFile:cerPath];NSSet * certSet = [[NSSet alloc] initWithObjects:certData, nil]; AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];// 是否允许,NO-- 不允许无效的证书[securityPolicy setAllowInvalidCertificates:YES];// 设置证书[securityPolicy setPinnedCertificates:certSet]; AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; manager.securityPolicy = securityPolicy; manager.responseSerializer = [AFHTTPResponseSerializer serializer];// request[manager GET:urlString parameters:nil progress:^(NSProgress * progress){ } success:^(NSURLSessionDataTask *task, id responseObject) { NSArray * array = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableLeaves error:nil]; NSLog(@"OK === %@",array); } failure:^(NSURLSessionDataTask *task, NSError *error) { NSLog(@"error ==%@",error.description); }];
然后,就OK了。
六、注意下服务器端两种证书的区别
第一种是创建证书请求,然后到权威机构认证,随之配置到服务器;
第二种是自建证书,需要自己配置给服务器。
使用第一种还是好一点的,至少在我们 app 端不需要为ATS做过多的适配。但是如何才能知道一个HTTPS服务器是否符合ATS特性中的要求的呢?使用nscurl命令:
nscurl --ats-diagnostics --verbose https://example.com
下面是测百度时,返回的某一段,结论是OK的,里面有很多测试的情况,我们可以逐一观察是否正确。
TLSv1.0 with PFS disabled and insecure HTTP allowed ATS Dictionary:{ NSExceptionDomains = { "www.baidu.com" = { NSExceptionAllowsInsecureHTTPLoads = true; NSExceptionMinimumTLSVersion = "TLSv1.0"; NSExceptionRequiresForwardSecrecy = false; }; };} Result : PASS
PS:现在我新公司的项目这边是都不要做之前那种调整适配的,使用是第一种 权威 CA 颁发的那种证书,我们 APP 这端实际上真正的工作量是没有多少的,所以说关于HTTPS 适配的这块:
可以说:在购买到合法的证书时,我们 App 端 基本什么都不用管,改一下URL就好啦。