其实HTTPS从最终的数据解析的角度,与HTTP没有任何的区别,HTTPS就是将HTTP协议数据包放到SSL/TSL层加密后,在TCP/IP层组成IP数据报去传输,以此保证传输数据的安全;而对于接收端,在SSL/TSL将接收的数据包解密以后,将数据传给HTTP协议层,就是普通的HTTP数据。HTTP和SSL/TSL都处于OSI模型的应用层。从HTTP切换到HTTPS是一个很是简单的过程,在作具体的切换操做以前,咱们须要了解几个概念:html
为了保证这些隐私数据能加密传输,因而网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。SSL目前的版本是3.0,被IETF(Internet Engineering Task Force)定义在RFC 6101中,以后IETF对SSL 3.0进行了升级,因而出现了TLS(Transport Layer Security) 1.0,定义在RFC 2246。实际上咱们如今的HTTPS都是用的TLS协议,可是因为SSL出现的时间比较早,而且依旧被如今浏览器所支持,所以SSL依然是HTTPS的代名词,但不管是TLS仍是SSL都是上个世纪的事情,SSL最后一个版本是3.0,从此TLS将会继承SSL优良血统继续为咱们进行加密服务。web
简单的来讲,SSL/TSL经过四次握手。SSL协议的工做流程:安全
服务器认证阶段:服务器
客户端向服务器发送一个开始信息“Hello”以便开始一个新的会话链接;
服务器根据客户的信息肯定是否须要生成新的主密钥,如须要则服务器在响应客户的“Hello”信息时将包含生成主密钥所需的信息;
客户根据收到的服务器响应信息,产生一个主密钥,并用服务器的公开密钥加密后传给服务器;
服务器恢复该主密钥,并返回给客户一个用主密钥认证的信息,以此让客户认证服务器。微信
用户认证阶段:网络
在此以前,服务器已经经过了客户认证,这一阶段主要完成对客户的认证。
经认证的服务器发送一个提问给客户,客户则返回(数字)签名后的提问和其公开密钥,从而向服务器提供认证。app
iOS9中新增App Transport Security(简称ATS)特性, 主要使到原来请求的时候用到的HTTP,都转向TLS1.2协议进行传输。这也意味着全部的HTTP协议都强制使用了HTTPS协议进行传输。在 iOS 9 和 OS X 10.11 中,默认状况下非 HTTPS 的网络访问是被禁止的。固然,由于这样的推动影响面很是广,做为缓冲,咱们能够在 Info.plist 中添加 NSAppTransportSecurity
字典而且将 NSAllowsArbitraryLoads
设置为 YES
来禁用 ATS。框架
不过,WWDC 16 中,Apple 表示将继续在 iOS 10 和 macOS 10.12 里收紧对普通 HTTP 的访问限制。从 2017 年 1 月 1 日起,全部的新提交 app 默认是不容许使用 NSAllowsArbitraryLoads
来绕过 ATS 限制的,也就是说,咱们最好保证 app 的全部网络请求都是 HTTPS 加密的,不然可能会在应用审核时遇到麻烦。
经过在info.plist中配置这个键,开发者能够自定义网络安全策略。例如:
容许针对个别服务器的不安全访问。
容许不安全的 web 或媒体内容访问,但不影响整个app的ATS策略。
启用新的安全特性,例如Certificate Transparency。
对NSAppTransportSecurity的支持自 iOS9.0,OS X v10.11 开始,适用于 app 和 app extension。
自 iOS10.0,macOS 10.12 开始,增长了对下列子键的支持:
对于使用 iOS9.0, OS X v10.11 SDK 及以上的 app 来讲,ATS(App Transport Security)默认开启,NSAllowsArbitraryLoads是字典NSAppTransportSecurity的根键,默认值NO。
在启用 ATS 的状况下,全部的 HTTP 请求必须为 HTTPS(RFC 2818) 链接。任何不安全的 HTTP 请求都将失败。ATS 使用 TLS(Transport Layer Security)v1.2(RFC 5246)。
下面是字典NSAppTransportSecurity的整体结构,全部键都是非必填项:
NSAppTransportSecurity : Dictionary { NSAllowsArbitraryLoads : Boolean NSAllowsArbitraryLoadsInMedia : Boolean NSAllowsArbitraryLoadsInWebContent : Boolean NSAllowsLocalNetworking : Boolean NSExceptionDomains : Dictionary { <domain-name-string> : Dictionary { NSIncludesSubdomains : Boolean NSExceptionAllowsInsecureHTTPLoads : Boolean NSExceptionMinimumTLSVersion : String NSExceptionRequiresForwardSecrecy : Boolean // Default value is YES NSRequiresCertificateTransparency : Boolean } } }
能够看出,全部键能够分为两类:主键,这些键用来定义 app 的整体 ATS 策略;子键,即NSExceptionDomains下面的键,使用这些键针对某个域名单独配置。
主键包括:
NSAllowsArbitraryLoads
设置为 YES,解除整个 app 的 ATS 限制;可是,经过NSExceptionDomains进 行的配置依然有效。默认值为 NO。
注意:设置为 YES,会引起 App Stroe 的审查,开发者必须说明缘由。
NSAllowsArbitraryLoadsInMedia
设置为 YES,解除经过 AV Foundation 框架访问媒体内容时的 ATS 限制;启用这个 键,务必确保载入的媒体内容已经被加密,例如受FairPlay保护的文件,或者是安全的 HLS流媒,其中不包含敏感的我的信息。默认为 NO。
NSAllowsArbitraryLoadsInWebContent
设置为 YES,解除经过 web view 发出的网络请求的 ATS 限制。启用这个键,可使 app 访问任意网页内容,但不影响 app 的整体 ATS 策略。此键值默认为 NO。
NSAllowsLocalNetworking
设置为 YES,使得 app 能够载入任意本地资源,但不影响 app 的整体 ATS 策略。默 认为 NO。
NSExceptionDomains
为一个或多个域名单独配置 ATS。
被单独配置的域名,默认受到彻底的 ATS 限制,无论NSAllowsArbitraryLoads的值 如何;须要经过子键,进一步配置
全部的子键都属于NSExceptionDomain。向Info.plist中添加这一主键:
例如,及时以前设置NSAllowsArbitraryLoadsInMedia为 YES,然而NSExceptionDomain所表明的域名依然不能访问不安全的媒体内容。
基于这样的设定,能够针对域名进行 ATS 配置,增长或减小安全措施。例如:
NSExceptionDomains字典构成:
<域名字符串>
表明想要配置的特定域名。能够添加多个域名(即添加多个这样的键),为它们统一配置 ATS 策略。这个键对应一个字典,包含如下子键:
* 设置为 YES,当前域名的 ATS 策略适用于其全部子域名。默认为 NO。
* 设置为 YES,能够同时经过 HTTP 和 HTTPS 访问当前域名。默认为 NO。 注意,配置这个键值,将引起 App Store 的审查,开发者必须说明缘由。
* 指定 TLS 的最低版本,所以可使用版本较低,有安全漏洞的 TLS 协议。 注意,配置这个键值,将引起 App Store 的审查,开发者必须说明缘由。
* 设置为 NO,容许针对当前域名使用不支持正向保密的 TLS 加密算法。默认为 YES。
* 设置为 YES,将验证域名服务器证书的Certificate Transparency时间戳 。默认为 NO。
在 ATS 彻底开启的状况下,系统要求 app 的 HTTPS 链接必须知足如下要求:
X.509 数字证书必须知足下列标准中的一项:
由操做系统内嵌的根证书颁发机构签发
链接必须使用 AES-128 或 AES-256 对称加密算法。 TLS 算法套装必须以 ECDSA 密钥交换的形式支持正向保密,加密算法必须为下面之一:
服务端的叶证书签名密钥必须为下面之一:
某些对 ATS 的配置会引起 App Store 的审核,开发者必须说明缘由。这些键有:
如下是一些缘由说明例子,供参考:
向 App Store 提交审核时,开发者应主动提供足够的信息,以便解释 app 没法使用安全链接的缘由。
<font color=red size=5>ATS相关设置对iOS8及如下系统无效</font>
Info.plist文件是向操做系统描述应用程序的XML属性列表,是iPhone应用程序文件夹包含全部重要的Info.plist文件
你可能注意到一些关键字像是使用了一些其余关键字中的词可是在前面加上了"ThirdParty"字样,在功能上,这些关键字与不含有"ThirdParty"的关键字有一样的效果。并且实际运行中所调用的代码将会彻底忽略是否使用"ThirdParty"关键字。
简单粗暴的方案:
--------------------------------------------
NSExceptionDomains 的设置方法以下, 好比咱们要将 weibo.com 这个域名排除在 ATS 验证以外,就能够这样:
key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>weibo.com</key> <dict> <key> NSIncludesSubdomains </key> <true/> <key> NSExceptionRequiresForwardSecrecy </key> <false/> <key>NSExceptionAllowsInsecureHTTPLoads</key> <true/> </dict> </dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
注意:每一个需添加的域都须要设置此三个属性。若是请求的网络图片是HTTP,也是须要设置的图片的域。
注意⚠️这个方案风险较大,有可能被拒绝。“须要访问的域名是第三方服务器,他们没有进行 HTTPS 对应”会是审核时的一个可选理由,可是这应该只须要针对特定域名,而非全面开放。若是访问的是本身的服务器的话,可能这个理由会没法经过。
------------------------------------------------
解决方案:
搭建https服务器
搭建https服务器须要ssl证书
HTTPS服务器知足ATS默认的条件,并且SSL证书是经过权威的CA机构认证过的,那么咱们在使用Xcode开发的时候,对网络的适配什么都不用作,咱们也能正常与服务器通讯。可是,当咱们对安全性有更高的要求时或者咱们自建证书时,咱们须要本地导入证书来进行验证。
使用AFNetworking来支持https
AFNetworking是iOS/OSX开发最流行的第三方开源库之一,如今iOS oc 代码90%以上都是用这个框架网络请求。AFNetworking已经将上面的逻辑代码封装好,甚至更完善,在AFSecurityPolicy文件中,有兴趣能够阅读这个模块的代码;如下就是在AFNetworking 2.6.0之前版本和3.0.0版本基于支持https的验证方式
步骤:
代码实现:
NSURL * url = [NSURL URLWithString:@"https://www.google.com"]; AFHTTPRequestOperationManager * requestOperationManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:url]; dispatch_queue_t requestQueue = dispatch_create_serial_queue_for_name("kRequestCompletionQueue"); requestOperationManager.completionQueue = requestQueue; AFSecurityPolicy * securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; //allowInvalidCertificates 是否容许无效证书(也就是自建的证书),默认为NO //若是是须要验证自建证书,须要设置为YES securityPolicy.allowInvalidCertificates = YES; //validatesDomainName 是否须要验证域名,默认为YES; //假如证书的域名与你请求的域名不一致,需把该项设置为NO;如设成NO的话,即服务器使用其余可信任机构颁发的证书,也能够创建链接,这个很是危险,建议打开。 //置为NO,主要用于这种状况:客户端请求的是子域名,而证书上的是另一个域名。由于SSL证书上的域名是独立的,假如证书上注册的域名是www.google.com,那么mail.google.com是没法验证经过的;固然,有钱能够注册通配符的域名*.google.com,但这个仍是比较贵的。 //如置为NO,建议本身添加对应域名的校验逻辑。 securityPolicy.validatesDomainName = YES; //validatesCertificateChain 是否验证整个证书链,默认为YES //设置为YES,会将服务器返回的Trust Object上的证书链与本地导入的证书进行对比,这就意味着,假如你的证书链是这样的: //GeoTrust Global CA // Google Internet Authority G2 // *.google.com //那么,除了导入*.google.com以外,还须要导入证书链上全部的CA证书(GeoTrust Global CA, Google Internet Authority G2); //如是自建证书的时候,能够设置为YES,加强安全性;假如是信任的CA所签发的证书,则建议关闭该验证,由于整个证书链一一比对是彻底没有必要(请查看源代码); securityPolicy.validatesCertificateChain = NO; requestOperationManager.securityPolicy = securityPolicy;
另afnetworking 3.0.0以上版本用的是AFHTTPSessionManager
AFHTTPSessionManager * manager = [AFHTTPSessionManager manager];
NSString * cerPath = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"cer"]; NSData * cerData = [NSData dataWithContentsOfFile:cerPath]; NSLog(@"%@", cerData); manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[[NSArray alloc] initWithObjects:cerData, nil]]; manager.securityPolicy.allowInvalidCertificates = YES; [manager.securityPolicy setValidatesDomainName:NO]; manager.requestSerializer = [AFJSONRequestSerializer serializer]; manager.responseSerializer = [AFJSONResponseSerializer serializer]; NSDictionary * parameter = @{@"username":self.username, @"password":self.password}; [manager POST:@"https://192.168.1.4:9777" parameters:parameter success:^(NSURLSessionDataTask * task, id responseObject) { NSLog(@"success %@", responseObject); } failure:^(NSURLSessionDataTask * task, NSError * error) { NSLog(@"failure %@", error); }]
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> //设置为 YES,解除整个app的ATS限制;可是经过NSExceptionDomains进行的配置依然有效 <false/> <key>NSAllowsArbitraryLoadsInMedia</key> //设置为 YES,解除经过AVFoundation框架访问媒体内容时的 ATS 限制 <true/> <key>NSAllowsArbitraryLoadsInWebContent</key> //设置为 YES,解除经过webview发出的网络请求的ATS限制 <true/> <key>NSAllowsLocalNetworking</key> //设置为 YES,使得app能够载入任意本地资源,但不影响app的整体 ATS 策略 <true/>
对于网页浏览和视频播放的行为,iOS 10 中新加入了 NSAllowsArbitraryLoadsInWebContent 键。经过将它设置为 YES,可让 app 中的 WKWebView 和使用 AVFoundation 播放的在线视频不受 ATS 的限制。这也应该是绝大多数使用了相关特性的 app 的选择。可是坏消息是这个键在 iOS 9 中并不会起做用。
若是app只支持 iOS 10,而且有用户能够自由输入网址进行浏览的功能,或者是在线视频音频播放功能的话,简单地加入 NSAllowsArbitraryLoadsInWebContent,而且将组件换成 WKWebKit 或者 AVFoundation 就能够了。若是你还须要支持 iOS 9,而且须要访问网页和视频的话,可能只能去开启 NSAllowsArbitraryLoads 而后提交时进行说明,而且看 Apple 审核员决定让不让经过了。
另外,当 NSAllowsArbitraryLoads 和 NSAllowsArbitraryLoadsInWebContent 同时存在时,根据系统不一样,表现的行为也会不同。简单说,iOS 9 只看 NSAllowsArbitraryLoads,而 iOS 10 会先看 NSAllowsArbitraryLoadsInWebContent。在 iOS 10 中,要是 NSAllowsArbitraryLoadsInWebContent 存在的话,就忽略掉 NSAllowsArbitraryLoads,若是它不存在,则遵循 NSAllowsArbitraryLoads 的设定
UIWebView 在 NSAllowsArbitraryLoadsInWebContent 为 YES 时访问 HTTP,无效。WKWebView 在 NSAllowsArbitraryLoadsInWebContent 为 YES 时在iOS 10 中访问 HTTP,有效,iOS 9无效。若是用WkWebView替换UIWebView,iOS 7 将没法使用WkWebView,可作适配加载,没有特殊的什么需求的话,尽早将 UIWebView 所有换为 WkWebView 会比较好。因此为了能让WebView在全部版本都能访问非https内容,只能把NSAllowsArbitraryLoads设置为YES。
解决方案一:
开启 NSAllowsArbitraryLoads 为 YES,而后提交时进行说明
解决方案二:
设置 NSExceptionDomains 属性来访问指定域名,而后提交时进行说明
可是按照国内的现状,关闭这个限制也许是更实际的作法。至于缘由就太多了,第三方SDK(几乎都是访问http),合做伙伴接入(不能要求它们必定要支持https)
第三方sdk,一样须要遵照ATS规则,即第三方sdk也有被ATS过滤的风险,微信,qq,分享,登录功能都能正常,微博登录不能正常经过。另在网上找到了一些可能存在有问题的sdk,目前已知的有:
解决方案一:
更新最新sdk,接入并测试
解决方案二:
能够设置 NSExceptionDomains属性来将须要排除强制验证的域名写进来:
开启 NSAllowsArbitraryLoads 为 YES
对第三方访问的服务器设置NSExceptionDomains方式添加白名单
提交审核说明:
必须链接由其余机构控制的服务器,其还不支持安全链接。
必须经过 web 展现来源不一的各类网络内容,但又不能彻底使用NSAllowsArbitraryLoadsInWebContent所管理的类。