iOS AFNetworking框架HTTPS请求配置
2017-11-24 00:00
369 查看
摘要: iOS在Apple公司的强制要求下,数据传输必须按照ATS(App Transefer Security)条款。关于AFNetworking框架传输HTTPS数据。
一.AllowsArbitraryLoads 白名单机制
NSAllowsArbitraryLoads是ATS推广过程中的产物,当然也许可持续很久甚至永久,为了访问HTTP服务,一般需要绕过ATS限制,需要配置info.plist文件
这种机制实际上是允许了所有HTTP 和HTTPS的访问,显然,这种做法实际上很危险。设置为false就能避免绕开ATS,问题是我们真的需要完全关闭这个选项么?
比如某些文件服务器,CDN服务器配置HTTPS反而影响传输速度,这种情况下HTTP反而具有很高的优越性。因此,对于这类服务器的HTTP传输,我们其实也可以使用如下方式(设置白名单),白名单之外的必须使用HTTPS协议。
二.免证书验证
免证书验证,一般来说是client证书库不会把server传输来的证书进行校验。
举个例子
这种方式导致我们的app容易遭到中间人攻击,原因并不完全是我们设置了allowInvalidCertificates=YES 和validatesDomainName=NO,而是本地证书库中没有添加server的CA证书,只要是任意的https都能伪造为服务器。
因此,我们并不推荐使用这种方式。
三.证书验证
3.1 加密标准分类
证书验证分为2类,一类是单向认证,一类是双认证。
此外,我们还需要区分证书与证书库的区别,证书库类型包括PKCS12,JKS,BKS等,其中,PKCS12是互联网标准,可以跨平台跨语言(支持Android,iOS,WP,PC,JAVA,PHP...),JKS是Java标准,只能在Java平台和Java语言下使用,BKS是 Bouncy Castle公司的加密标准,作为Android平台支持SSL/TLS加密套件PKCS12的补充,其加密强度很高,但是目前只用于Android平台。证书的定义是保存在证书库中的数字签名信息或者单独的证书文件,如crt,pem,cer等文件。在说加密之前,先来看看自签名证书。
3.2 自签名证书 vs 第三方权威机构证书
有人可能会有疑问,自签名证书和第三方权威机构的证书的效用是否一样?
实际上本人认为完全一样,在互联网中,基于B/S架构的服务中,B端通常导入了第三方权威机构的根证书(ROOT CA),实际上就是为了验证网站的CA证书是不是安全的,并且验证是不是由权威的安全机构签发的证书。问题是,我们的App与Server是C/S架构,每个app最多也就只能访问有限的几个网址,我们自己做的app实际上本身就是信任自己的所设置的站点URL的,也就是说我们自己人相信自己人。我们的证书只是为了数据安全传输,不被中间人攻击,因此完全没必要使用(ROOT CA),但是具体来说,到目前为止也没人试过这种方式是否可以通过审核。
我试图找第三方CA证书机构交流,貌似他只是说这是苹果的规定,实际上自签名证书本质上没什么问题,只要密钥长度,复杂度,加密方式等达到要求即可。
因此,苹果如果真的要求必须使用第三方CA ROOT签名的规则,本身是不合理的。这些问题也没法避免,不过,如果苹果允许自签名证书的话,设置allowInvalidCertificates=YES即可。
3.3 单向认证
需要准备的文件:服务端证书库 , 服务端导出的证书
单向认证,实际上说的是只有Client端对Server端的证书进行验证,Server不需要验证Client端的证书。
自定义类:MyAFNetworking
注意:以上说的证书是从服务器端到处的cer或者crt证书,这类证书是X509 Der格式的二进制编码证书,不是X509 PAM格式的Base64编码证书,关于自签名证书的生成请参考如下地址
常见证书格式及相互转换
iOS非对称加解密
iOS 自签名证书建立(self-signed)
3.4 双向认证
iOS和Android一样,客户端证书库类型可以是PKCS12类型的pfx证书,此类证书包含私钥,公钥和证书,并且由密码。
双向认证一般用于安全要求比较高的产品,比如金融类app,政府app等特殊行业。
需要准备的文件:服务端证书库,服务端证书信任库 , 服务端导出的证书,客户端证书库,客户端证书
注[1]:服务端证书库可以和服务端信任证书库使用同一个证书库,唯一要做的是把客户端证书导入进行。
注[2]:客户端证书一般使用跨平台的PKCS12证书库(pfx或p12),必须记住证书库密钥,此类证书库同时包含私钥,公钥和证书。
3.4.1 信任服务器
本步骤用来校验客户端证书,和单向认证完全相同
自定义类:MyAFNetworking
3.4.2 提供客户端证书和证书库
通过以上方式,我们便能实现双向认证了
【编辑推荐】
iOS:如何捕获异常?
iOS单元测试和UI测试全面解析
基于iOS 10.3,开发者如何与用户更好地“沟通”
iOS自动化测试的那些干货
iOS编译过程的原理和应用
一.AllowsArbitraryLoads 白名单机制
NSAllowsArbitraryLoads是ATS推广过程中的产物,当然也许可持续很久甚至永久,为了访问HTTP服务,一般需要绕过ATS限制,需要配置info.plist文件
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
这种机制实际上是允许了所有HTTP 和HTTPS的访问,显然,这种做法实际上很危险。设置为false就能避免绕开ATS,问题是我们真的需要完全关闭这个选项么?
比如某些文件服务器,CDN服务器配置HTTPS反而影响传输速度,这种情况下HTTP反而具有很高的优越性。因此,对于这类服务器的HTTP传输,我们其实也可以使用如下方式(设置白名单),白名单之外的必须使用HTTPS协议。
<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>lib.baidu.com</key> <dict> <key>NSIncludesSubdomains</key> <true/> </dict> <key>oss.fastdfs.cn</key> <dict> <key>NSIncludesSubdomains</key> <true/> </dict> </dict> </dict>
二.免证书验证
免证书验证,一般来说是client证书库不会把server传输来的证书进行校验。
举个例子
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; //允许非权威机构颁发的证书 manager.securityPolicy.allowInvalidCertificates = YES; //也不验证域名一致性 manager.securityPolicy.validatesDomainName = NO; //关闭缓存避免干扰测试 manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData; [manager GET:@"https://www.baidu.com/s?wd=https" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"%@",responseObject); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"%@",error); }];
这种方式导致我们的app容易遭到中间人攻击,原因并不完全是我们设置了allowInvalidCertificates=YES 和validatesDomainName=NO,而是本地证书库中没有添加server的CA证书,只要是任意的https都能伪造为服务器。
因此,我们并不推荐使用这种方式。
三.证书验证
3.1 加密标准分类
证书验证分为2类,一类是单向认证,一类是双认证。
此外,我们还需要区分证书与证书库的区别,证书库类型包括PKCS12,JKS,BKS等,其中,PKCS12是互联网标准,可以跨平台跨语言(支持Android,iOS,WP,PC,JAVA,PHP...),JKS是Java标准,只能在Java平台和Java语言下使用,BKS是 Bouncy Castle公司的加密标准,作为Android平台支持SSL/TLS加密套件PKCS12的补充,其加密强度很高,但是目前只用于Android平台。证书的定义是保存在证书库中的数字签名信息或者单独的证书文件,如crt,pem,cer等文件。在说加密之前,先来看看自签名证书。
3.2 自签名证书 vs 第三方权威机构证书
有人可能会有疑问,自签名证书和第三方权威机构的证书的效用是否一样?
实际上本人认为完全一样,在互联网中,基于B/S架构的服务中,B端通常导入了第三方权威机构的根证书(ROOT CA),实际上就是为了验证网站的CA证书是不是安全的,并且验证是不是由权威的安全机构签发的证书。问题是,我们的App与Server是C/S架构,每个app最多也就只能访问有限的几个网址,我们自己做的app实际上本身就是信任自己的所设置的站点URL的,也就是说我们自己人相信自己人。我们的证书只是为了数据安全传输,不被中间人攻击,因此完全没必要使用(ROOT CA),但是具体来说,到目前为止也没人试过这种方式是否可以通过审核。
我试图找第三方CA证书机构交流,貌似他只是说这是苹果的规定,实际上自签名证书本质上没什么问题,只要密钥长度,复杂度,加密方式等达到要求即可。
因此,苹果如果真的要求必须使用第三方CA ROOT签名的规则,本身是不合理的。这些问题也没法避免,不过,如果苹果允许自签名证书的话,设置allowInvalidCertificates=YES即可。
3.3 单向认证
需要准备的文件:服务端证书库 , 服务端导出的证书
单向认证,实际上说的是只有Client端对Server端的证书进行验证,Server不需要验证Client端的证书。
自定义类:MyAFNetworking
+ (AFHTTPSessionManager *)manager; { static AFHTTPSessionManager *shareInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; shareInstance = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:BaseHttpURLString] sessionConfiguration:configuration]; //设置请求参数的类型:JSON shareInstance.requestSerializer = [AFJSONRequestSerializer serializer]; //设置服务器返回结果的类型:JSON (AFJSONResponseSerializer,AFHTTPResponseSerializer) shareInstance.responseSerializer = [AFJSONResponseSerializer serializer]; //设置请求的超时时间 shareInstance.requestSerializer.timeoutInterval = 20.0f; //设置ContentType shareInstance.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", @"text/json", @"text/plain", @"text/javascript", @"text/xml", @"image/jpeg",@"image/png", nil]; // https配置 NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"你的证书名" ofType:@"cer"]; NSData *certData = [NSData dataWithContentsOfFile:cerPath]; AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[[NSSet alloc] initWithObjects:certData, nil]]; NSSet *dataSet = [[NSSet alloc] initWithObjects:certData, nil]; //这里可以添加多个server的证书 // setPinnedCertificates 设置证书文件(可能不止一个证书) [securityPolicy setPinnedCertificates:dataSet]; // allowInvalidCertificates 是否允许无效证书 [securityPolicy setAllowInvalidCertificates:NO]; // validatesDomainName 是否需要验证域名 [securityPolicy setValidatesDomainName:YES]; shareInstance.securityPolicy = securityPolicy; }); return shareInstance; }
注意:以上说的证书是从服务器端到处的cer或者crt证书,这类证书是X509 Der格式的二进制编码证书,不是X509 PAM格式的Base64编码证书,关于自签名证书的生成请参考如下地址
常见证书格式及相互转换
iOS非对称加解密
iOS 自签名证书建立(self-signed)
3.4 双向认证
iOS和Android一样,客户端证书库类型可以是PKCS12类型的pfx证书,此类证书包含私钥,公钥和证书,并且由密码。
双向认证一般用于安全要求比较高的产品,比如金融类app,政府app等特殊行业。
需要准备的文件:服务端证书库,服务端证书信任库 , 服务端导出的证书,客户端证书库,客户端证书
注[1]:服务端证书库可以和服务端信任证书库使用同一个证书库,唯一要做的是把客户端证书导入进行。
注[2]:客户端证书一般使用跨平台的PKCS12证书库(pfx或p12),必须记住证书库密钥,此类证书库同时包含私钥,公钥和证书。
3.4.1 信任服务器
本步骤用来校验客户端证书,和单向认证完全相同
自定义类:MyAFNetworking
+ (AFHTTPSessionManager *)manager; { static AFHTTPSessionManager *shareInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; shareInstance = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:BaseHttpURLString] sessionConfiguration:configuration]; //设置请求参数的类型:JSON shareInstance.requestSerializer = [AFJSONRequestSerializer serializer]; //设置服务器返回结果的类型:JSON (AFJSONResponseSerializer,AFHTTPResponseSerializer) shareInstance.responseSerializer = [AFJSONResponseSerializer serializer]; //设置请求的超时时间 shareInstance.requestSerializer.timeoutInterval = 20.0f; //设置ContentType shareInstance.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", @"text/json", @"text/plain", @"text/javascript", @"text/xml", @"image/jpeg",@"image/png", nil]; // https配置 NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"你的证书名" ofType:@"cer"]; NSData *certData = [NSData dataWithContentsOfFile:cerPath]; AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[[NSSet alloc] initWithObjects:certData, nil]]; NSSet *dataSet = [[NSSet alloc] initWithObjects:certData, nil]; //这里可以添加多个server的证书 // setPinnedCertificates 设置证书文件(可能不止一个证书) [securityPolicy setPinnedCertificates:dataSet]; // allowInvalidCertificates 是否允许无效证书 [securityPolicy setAllowInvalidCertificates:NO]; // validatesDomainName 是否需要验证域名 [securityPolicy setValidatesDomainName:YES]; shareInstance.securityPolicy = securityPolicy; }); return shareInstance; }
3.4.2 提供客户端证书和证书库
/* * ** * 创建服务器信任客户端的认证条件 ** */ +(AFHTTPSessionManager *) createCredentialsClient { __block AFHTTPSessionManager * manager = [MyAFNetworking manager]; [manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession*session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing*_credential) { NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; __autoreleasing NSURLCredential *credential =nil; if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { if([manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) { credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; if(credential) { disposition =NSURLSessionAuthChallengeUseCredential; } else { disposition =NSURLSessionAuthChallengePerformDefaultHandling; } } else { disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; } } else { // client authentication SecIdentityRef identity = NULL; SecTrustRef trust = NULL; NSString *p12 = [[NSBundle mainBundle] pathForResource:@"client"ofType:@"pfx"]; NSFileManager *fileManager =[NSFileManager defaultManager]; if(![fileManager fileExistsAtPath:p12]) { NSLog(@"client.p12:not exist"); } else { NSData *PKCS12Data = [NSData dataWithContentsOfFile:p12]; #加载PKCS12证书,pfx或p12 if ([MyAFNetworking extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data]) { SecCertificateRef certificate = NULL; SecIdentityCopyCertificate(identity, &certificate); const void*certs[] = {certificate}; CFArrayRef certArray =CFArrayCreate(kCFAllocatorDefault, certs,1,NULL); credential =[NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray*)certArray persistence:NSURLCredentialPersistencePermanent]; disposition =NSURLSessionAuthChallengeUseCredential; } } } *_credential = credential; return disposition; }]; return manager; } /** **加载PKCS12证书,pfx或p12 ** **/ +(BOOL)extractIdentity:(SecIdentityRef*)outIdentity andTrust:(SecTrustRef *)outTrust fromPKCS12Data:(NSData *)inPKCS12Data { OSStatus securityError = errSecSuccess; //client certificate password NSDictionary*optionsDictionary = [NSDictionary dictionaryWithObject:@"你的p12密码" forKey:(__bridge id)kSecImportExportPassphrase]; CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); securityError = SecPKCS12Import((__bridge CFDataRef)inPKCS12Data,(__bridge CFDictionaryRef)optionsDictionary,&items); if(securityError == 0) { CFDictionaryRef myIdentityAndTrust =CFArrayGetValueAtIndex(items,0); const void*tempIdentity =NULL; tempIdentity= CFDictionaryGetValue (myIdentityAndTrust,kSecImportItemIdentity); *outIdentity = (SecIdentityRef)tempIdentity; const void*tempTrust =NULL; tempTrust = CFDictionaryGetValue(myIdentityAndTrust,kSecImportItemTrust); *outTrust = (SecTrustRef)tempTrust; } else { NSLog(@"Failedwith error code %d",(int)securityError); return NO; } return YES; }
通过以上方式,我们便能实现双向认证了
AFHTTPSessionManager * manager = [MyAFNetworking createCredentialsClient];
【编辑推荐】
iOS:如何捕获异常?
iOS单元测试和UI测试全面解析
基于iOS 10.3,开发者如何与用户更好地“沟通”
iOS自动化测试的那些干货
iOS编译过程的原理和应用
相关文章推荐
- iOS开发 支持https请求以及ssl证书配置(转)
- iOS 开发 https问题使用AFN进行网络请求时做的一些配置
- iOS开发 AFN配置https请求
- iOS开发 支持https请求以及ssl证书配置
- iOS开发 支持https请求以及ssl证书配置
- iOS中https的网络请求的配置
- IOS开发 支持https请求以及ssl证书配置详解
- iOS开发 AFN配置https请求
- iOS开发工具-如何使用网络封包分析工具Charles,通过配置proxy对http、https、tcp、udp 等协议的请求响应过程交互信息进行分析、判断、解决我们移动开发中的遇到的各种实际问题。
- iOS开发 AFN配置https请求
- iOS用自签名证书实现HTTPS请求的原理实例讲解
- nginx 配置http请求重定向至https
- 十分钟学会Charles抓包(iOS的http/https请求)
- jboss tomcat 配置https请求方式
- 使用burpsuite监控设备(如ios,android)网络http,https请求
- [置顶] iOS使用自签名证书实现HTTPS请求
- 关于nginx配置ssl https请求访问出现EM_do_header:bad password read error:140B0009:SSL 错误
- iOS基于AFNetworking使用自签名证书实现HTTPS请求
- ios https 请求讲解
- Xcode7(iOS9 beta1)网络请求失败,配置info.plist文件解决--iOS开发