iOS AFNetworking框架HTTPS请求配置

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介:

iOS AFNetworking框架HTTPS请求配置

【引自IamOkay的博客】 iOS在Apple公司的强制要求下,数据传输必须按照ATS(App Transefer Security)条款。关于AFNetworking框架传输HTTPS数据。

一.AllowsArbitraryLoads 白名单机制

NSAllowsArbitraryLoads是ATS推广过程中的产物,当然也许可持续很久甚至永久,为了访问HTTP服务,一般需要绕过ATS限制,需要配置info.plist文件


  
  
  1. <key>NSAppTransportSecurity</key
  2. <dict> 
  3.         <key>NSAllowsArbitraryLoads</key
  4.         <true/> 
  5.  </dict>  

这种机制实际上是允许了所有HTTP 和HTTPS的访问,显然,这种做法实际上很危险。设置为false就能避免绕开ATS,问题是我们真的需要完全关闭这个选项么?

比如某些文件服务器,CDN服务器配置HTTPS反而影响传输速度,这种情况下HTTP反而具有很高的优越性。因此,对于这类服务器的HTTP传输,我们其实也可以使用如下方式(设置白名单),白名单之外的必须使用HTTPS协议。


  
  
  1. <key>NSAppTransportSecurity</key
  2.     <dict> 
  3.         <key>NSExceptionDomains</key
  4.         <dict> 
  5.             <key>lib.baidu.com</key
  6.             <dict> 
  7.                 <key>NSIncludesSubdomains</key
  8.                 <true/> 
  9.             </dict> 
  10.             <key>oss.fastdfs.cn</key
  11.             <dict> 
  12.                 <key>NSIncludesSubdomains</key
  13.                 <true/> 
  14.             </dict> 
  15.            </dict> 
  16.    </dict>  

二.免证书验证

免证书验证,一般来说是client证书库不会把server传输来的证书进行校验。

举个例子


  
  
  1. AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; 
  2. //允许非权威机构颁发的证书 
  3. manager.securityPolicy.allowInvalidCertificates = YES; 
  4. //也不验证域名一致性 
  5. manager.securityPolicy.validatesDomainName = NO
  6. //关闭缓存避免干扰测试 
  7. manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData; 
  8.  
  9. [manager GET:@"https://www.baidu.com/s?wd=https" parameters:nil progress:nil  
  10. success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) { 
  11.         NSLog(@"%@",responseObject); 
  12.     } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 
  13.         NSLog(@"%@",error); 
  14. }];  

这种方式导致我们的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


  
  
  1. + (AFHTTPSessionManager *)manager; 
  2.     static AFHTTPSessionManager *shareInstance = nil; 
  3.     static dispatch_once_t onceToken; 
  4.     dispatch_once(&onceToken, ^{ 
  5.  
  6.         NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 
  7.         shareInstance = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:BaseHttpURLString] sessionConfiguration:configuration]; 
  8.         //设置请求参数的类型:JSON 
  9.         shareInstance.requestSerializer = [AFJSONRequestSerializer serializer]; 
  10.         //设置服务器返回结果的类型:JSON (AFJSONResponseSerializer,AFHTTPResponseSerializer) 
  11.         shareInstance.responseSerializer = [AFJSONResponseSerializer serializer]; 
  12.         //设置请求的超时时间 
  13.         shareInstance.requestSerializer.timeoutInterval = 20.0f; 
  14.         //设置ContentType 
  15.         shareInstance.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", @"text/json", @"text/plain", @"text/javascript", @"text/xml", @"image/jpeg",@"image/png", nil]; 
  16.  
  17.         // https配置 
  18.         NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"你的证书名" ofType:@"cer"]; 
  19.         NSData *certData = [NSData dataWithContentsOfFile:cerPath]; 
  20.         AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[[NSSet alloc] initWithObjects:certData, nil]]; 
  21.  
  22.         NSSet *dataSet = [[NSSet alloc] initWithObjects:certData, nil]; //这里可以添加多个server的证书 
  23.  
  24.         // setPinnedCertificates 设置证书文件(可能不止一个证书) 
  25.         [securityPolicy setPinnedCertificates:dataSet]; 
  26.         // allowInvalidCertificates 是否允许无效证书 
  27.         [securityPolicy setAllowInvalidCertificates:NO]; 
  28.         // validatesDomainName 是否需要验证域名 
  29.         [securityPolicy setValidatesDomainName:YES]; 
  30.  
  31.         shareInstance.securityPolicy = securityPolicy; 
  32.     }); 
  33.     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


  
  
  1. + (AFHTTPSessionManager *)manager; 
  2.     static AFHTTPSessionManager *shareInstance = nil; 
  3.     static dispatch_once_t onceToken; 
  4.     dispatch_once(&onceToken, ^{ 
  5.  
  6.         NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 
  7.         shareInstance = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:BaseHttpURLString] sessionConfiguration:configuration]; 
  8.         //设置请求参数的类型:JSON 
  9.         shareInstance.requestSerializer = [AFJSONRequestSerializer serializer]; 
  10.         //设置服务器返回结果的类型:JSON (AFJSONResponseSerializer,AFHTTPResponseSerializer) 
  11.         shareInstance.responseSerializer = [AFJSONResponseSerializer serializer]; 
  12.         //设置请求的超时时间 
  13.         shareInstance.requestSerializer.timeoutInterval = 20.0f; 
  14.         //设置ContentType 
  15.         shareInstance.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", @"text/json", @"text/plain", @"text/javascript", @"text/xml", @"image/jpeg",@"image/png", nil]; 
  16.  
  17.         // https配置 
  18.         NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"你的证书名" ofType:@"cer"]; 
  19.         NSData *certData = [NSData dataWithContentsOfFile:cerPath]; 
  20.         AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[[NSSet alloc] initWithObjects:certData, nil]]; 
  21.  
  22.         NSSet *dataSet = [[NSSet alloc] initWithObjects:certData, nil]; //这里可以添加多个server的证书 
  23.  
  24.         // setPinnedCertificates 设置证书文件(可能不止一个证书) 
  25.         [securityPolicy setPinnedCertificates:dataSet]; 
  26.         // allowInvalidCertificates 是否允许无效证书 
  27.         [securityPolicy setAllowInvalidCertificates:NO]; 
  28.         // validatesDomainName 是否需要验证域名 
  29.         [securityPolicy setValidatesDomainName:YES]; 
  30.  
  31.         shareInstance.securityPolicy = securityPolicy; 
  32.     }); 
  33.     return shareInstance; 

3.4.2 提供客户端证书和证书库


  
  
  1. /* 
  2. ** 
  3. * 创建服务器信任客户端的认证条件 
  4. ** 
  5. */ 
  6. +(AFHTTPSessionManager *) createCredentialsClient 
  7. __block AFHTTPSessionManager * manager = [MyAFNetworking manager]; 
  8. [manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession*session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing*_credential) { 
  9.     NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; 
  10.     __autoreleasing NSURLCredential *credential =nil; 
  11.     if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { 
  12.         if([manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) { 
  13.             credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; 
  14.             if(credential) { 
  15.                 disposition =NSURLSessionAuthChallengeUseCredential; 
  16.             } else { 
  17.                 disposition =NSURLSessionAuthChallengePerformDefaultHandling; 
  18.             } 
  19.         } else { 
  20.             disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; 
  21.         } 
  22.     } else { 
  23.         // client authentication 
  24.         SecIdentityRef identity = NULL
  25.         SecTrustRef trust = NULL
  26.         NSString *p12 = [[NSBundle mainBundle] pathForResource:@"client"ofType:@"pfx"]; 
  27.         NSFileManager *fileManager =[NSFileManager defaultManager]; 
  28.  
  29.         if(![fileManager fileExistsAtPath:p12]) 
  30.         { 
  31.             NSLog(@"client.p12:not exist"); 
  32.         } 
  33.         else 
  34.         { 
  35.             NSData *PKCS12Data = [NSData dataWithContentsOfFile:p12]; 
  36.             #加载PKCS12证书,pfx或p12 
  37.             if ([MyAFNetworking extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data]) 
  38.             { 
  39.                 SecCertificateRef certificate = NULL
  40.                 SecIdentityCopyCertificate(identity, &certificate); 
  41.                 const void*certs[] = {certificate}; 
  42.                 CFArrayRef certArray =CFArrayCreate(kCFAllocatorDefault, certs,1,NULL); 
  43.                 credential =[NSURLCredential credentialWithIdentity:identity certificates:(__bridge  NSArray*)certArray persistence:NSURLCredentialPersistencePermanent]; 
  44.                 disposition =NSURLSessionAuthChallengeUseCredential; 
  45.             } 
  46.         } 
  47.     } 
  48.     *_credential = credential; 
  49.     return disposition; 
  50. }]; 
  51.  
  52. return manager; 
  53.  
  54. /** 
  55. **加载PKCS12证书,pfx或p12 
  56. **  
  57. **/ 
  58. +(BOOL)extractIdentity:(SecIdentityRef*)outIdentity andTrust:(SecTrustRef *)outTrust fromPKCS12Data:(NSData *)inPKCS12Data { 
  59.     OSStatus securityError = errSecSuccess; 
  60.     //client certificate password 
  61.     NSDictionary*optionsDictionary = [NSDictionary dictionaryWithObject:@"你的p12密码" 
  62.                                                                 forKey:(__bridge id)kSecImportExportPassphrase]; 
  63.  
  64.     CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); 
  65.     securityError = SecPKCS12Import((__bridge CFDataRef)inPKCS12Data,(__bridge CFDictionaryRef)optionsDictionary,&items); 
  66.  
  67.     if(securityError == 0) { 
  68.         CFDictionaryRef myIdentityAndTrust =CFArrayGetValueAtIndex(items,0); 
  69.         const void*tempIdentity =NULL
  70.         tempIdentity= CFDictionaryGetValue (myIdentityAndTrust,kSecImportItemIdentity); 
  71.         *outIdentity = (SecIdentityRef)tempIdentity; 
  72.         const void*tempTrust =NULL
  73.         tempTrust = CFDictionaryGetValue(myIdentityAndTrust,kSecImportItemTrust); 
  74.         *outTrust = (SecTrustRef)tempTrust; 
  75.     } else { 
  76.         NSLog(@"Failedwith error code %d",(int)securityError); 
  77.         return NO
  78.     } 
  79.     return YES; 

通过以上方式,我们便能实现双向认证了


  
  
  1. AFHTTPSessionManager * manager = [MyAFNetworking createCredentialsClient];  






作者:IamOkay
来源:51CTO
目录
相关文章
|
2月前
|
搜索推荐 数据管理 定位技术
iOS应用开发中有多种主流框架
iOS应用开发中有多种主流框架
256 60
|
1月前
|
iOS开发 开发者 MacOS
深入探索iOS开发中的SwiftUI框架
【10月更文挑战第21天】 本文将带领读者深入了解Apple最新推出的SwiftUI框架,这一革命性的用户界面构建工具为iOS开发者提供了一种声明式、高效且直观的方式来创建复杂的用户界面。通过分析SwiftUI的核心概念、主要特性以及在实际项目中的应用示例,我们将展示如何利用SwiftUI简化UI代码,提高开发效率,并保持应用程序的高性能和响应性。无论你是iOS开发的新手还是有经验的开发者,本文都将为你提供宝贵的见解和实用的指导。
127 66
|
5月前
|
物联网 区块链 vr&ar
未来已来:探索区块链、物联网与虚拟现实技术的融合与应用安卓与iOS开发中的跨平台框架选择
【8月更文挑战第30天】在科技的巨轮下,新技术不断涌现,引领着社会进步。本文将聚焦于当前最前沿的技术——区块链、物联网和虚拟现实,探讨它们各自的发展趋势及其在未来可能的应用场景。我们将从这些技术的基本定义出发,逐步深入到它们的相互作用和集成应用,最后展望它们如何共同塑造一个全新的数字生态系统。
|
2月前
|
iOS开发 开发者
探索iOS开发中的SwiftUI框架
【10月更文挑战第39天】在苹果的生态系统中,SwiftUI框架以其声明式语法和易用性成为开发者的新宠。本文将深入SwiftUI的核心概念,通过实际案例展示如何利用这一框架快速构建用户界面,并探讨其对iOS应用开发流程的影响。
|
3月前
|
移动开发 网络协议 小程序
基于开源IM即时通讯框架MobileIMSDK:RainbowChat-iOS端v9.1版已发布
RainbowChat是一套基于开源IM聊天框架 MobileIMSDK 的产品级移动端IM系统。RainbowChat源于真实运营的产品,解决了大量的屏幕适配、细节优化、机器兼容问题
77 5
|
2月前
|
开发框架 Dart Android开发
安卓与iOS的跨平台开发:Flutter框架深度解析
在移动应用开发的海洋中,Flutter作为一艘灵活的帆船,正引领着开发者们驶向跨平台开发的新纪元。本文将揭开Flutter神秘的面纱,从其架构到核心特性,再到实际应用案例,我们将一同探索这个由谷歌打造的开源UI工具包如何让安卓与iOS应用开发变得更加高效而统一。你将看到,借助Flutter,打造精美、高性能的应用不再是难题,而是变成了一场创造性的旅程。
|
3月前
|
Swift iOS开发 开发者
探索iOS开发中的SwiftUI框架
【10月更文挑战第21天】在苹果生态系统中,SwiftUI的引入无疑为iOS应用开发带来了革命性的变化。本文将通过深入浅出的方式,带领读者了解SwiftUI的基本概念、核心优势以及如何在实际项目中运用这一框架。我们将从一个简单的例子开始,逐步深入到更复杂的应用场景,让初学者能够快速上手,同时也为有经验的开发者提供一些深度使用的技巧和策略。
66 1
|
5月前
|
机器学习/深度学习 搜索推荐 数据处理
探索iOS应用开发的新趋势:SwiftUI和Combine框架
【8月更文挑战第6天】随着Apple不断推动其操作系统的进化,iOS开发领域也迎来了新的变革。本文将深入探讨SwiftUI和Combine框架如何革新iOS应用开发流程,提升开发者的工作效率,并改善最终用户的体验。我们将从这两个框架的基本概念出发,分析它们的核心优势,并预测它们将如何塑造iOS开发的未来。
|
4月前
|
前端开发 iOS开发 开发者
探索iOS开发中的SwiftUI框架
【9月更文挑战第21天】在iOS应用开发的广阔天地中,SwiftUI框架如一股清新之风,为开发者带来了声明式语法的便捷与高效。本文将深入探讨SwiftUI的核心概念、布局方式及数据绑定机制,同时通过实例演示如何运用SwiftUI构建用户界面,旨在引领读者领略SwiftUI的魅力,并激发其对iOS开发新趋势的思考与实践。
52 6
|
4月前
|
iOS开发 开发者 UED
探索iOS应用开发中的SwiftUI框架
【9月更文挑战第26天】 在iOS开发的海洋中,SwiftUI犹如一艘现代的快艇,引领着开发者们驶向更加高效与直观的编程体验。本文将带你领略SwiftUI的魅力,从其设计理念到实际应用,我们将一步步揭开它如何简化界面构建过程的面纱。通过对比传统方式,你将看到SwiftUI如何让代码变得像诗一样优美,同时保持强大的功能性和灵活性。准备好让你的iOS开发技能加速升级,一起驾驭这股新潮流吧!