6月14日在WWDC 2016开发者大会上,苹果宣布了一个最后期限:2017年1月1日起,所有提交到 App Store 的应用强制开启ATS(App Transport Security)安全功能。启用ATS后,它会屏蔽明文HTTP资源加载,强制App通过HTTPS连接网络服务,通过传输加密保障用户数据安全。
ATS在 iOS 9 中默认开启,但开发者仍然可以选择使用 NSAllowsArbitraryLoads来关闭 ATS,继续通过HTTP连接传输数据。但从 2017 年 1 月 1 日起,这招将行不通了,所有提交到 App Store 的App必须强制开启 ATS,否则将无法通过App Store的审核,影响应用上架。
1月9日更新:苹果宣布暂时延长iOS强制ATS的最后期限,给开发者更多时间做好准备,还没有确认新的截止日期,随时可能再次执行强制ATS。建议开发者停止观望,在时间充裕的情况下,尽快完成HTTPS升级方案。
一. 首先让你们的后台去购买SSL证书,正规的贵,淘宝上便宜,但是小心被骗,毕竟是和别人同用一个证书。自己考虑实际情况。单双域名你们考虑。
二.把你获得的证书转换成.cer文件,导入钥匙串中,然后把.cer文件添加到你的工程中。
三.在你封装的AF请求中加入如下方法
- (AFSecurityPolicy *)customSecurityPolicy
{
//先导入证书,找到证书的路径
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"api.napai.cn" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
//AFSSLPinningModeCertificate 使用证书验证模式
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
//allowInvalidCertificates 是否允许无效证书(也就是自建的证书),默认为NO
//如果是需要验证自建证书,需要设置为YES
securityPolicy.allowInvalidCertificates = NO;
//validatesDomainName 是否需要验证域名,默认为YES;
//假如证书的域名与你请求的域名不一致,需把该项设置为NO;如设成NO的话,即服务器使用其他可信任机构颁发的证书,也可以建立连接,这个非常危险,建议打开。
//置为NO,主要用于这种情况:客户端请求的是子域名,而证书上的是另外一个域名。因为SSL证书上的域名是独立的,假如证书上注册的域名是www.google.com,那么mail.google.com是无法验证通过的;当然,有钱可以注册通配符的域名*.google.com,但这个还是比较贵的。
//如置为NO,建议自己添加对应域名的校验逻辑。
securityPolicy.validatesDomainName = YES;
NSSet *set = [[NSSet alloc] initWithObjects:certData, nil];
securityPolicy.pinnedCertificates = set;
return securityPolicy;
}
上述的YES or NO一定要看好,我这个是可以实现验证的。
然后在你的AF对象中添加如下代码
AFHTTPSessionManager * manage = [[AFHTTPSessionManager alloc]initWithBaseURL:[NSURL URLWithString:requestHTTP]];
[manage setSecurityPolicy:[self customSecurityPolicy]];
将你的封装请求头http改为https。
四.注意你的plist文件
100%被拒的情况:
NSAllowsArbitraryLoads,打开此开关相当于关闭ATS。
NSExceptionAllowsInsecureHTTPLoads,使用自有网站的HTTP链接。
NSExceptionMinimumTLSVersion,使用自有网站低于TLS1.2标准的HTTPS链接。
以下几种情况是特例,不会被拒:
App提供流媒体服务,媒体源已经对内容进行了加密,这时只要使用苹果的AV Foundation框架加载内容,就可以无视ATS。
App的内容如果有来自已知的第三方,不过最好的做法是和第三方沟通下,敦促他们所有传输都使用TLS1.2加密。
App的内容来自于不可知的第三方,比如说允许用户通过App访问任意网站,比如说浏览器app,可以忽视ATS。
五、webview内支持任意http访问
对于网页浏览和视频播放的行为,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访问
但是按照国内的现状,关闭这个限制也许是更实际的做法。至于原因就太多了,第三方SDK(几乎都是访问http),合作伙伴接入(不能要求它们一定要支持https)
第三方sdk,同样需要遵守ATS规则,即第三方sdk也有被ATS过滤的风险,微信,qq,分享,登陆功能都能正常,微博登陆不能正常通过。另在网上找到了一些可能存在有问题的sdk,目前已知的有:
友盟 (已经有最新的v1.4.0版本sdk,支持https,待验证)百度地图
解决方案一:
更新最新sdk,接入并测试
解决方案二:
可以设置 NSExceptionDomains属性来将需要排除强制验证的域名写进来:
七. 总结
开启 NSAllowsArbitraryLoads 为 YES
对第三方访问的服务器设置NSExceptionDomains方式添加白名单
提交审核说明:
必须连接由其他机构控制的服务器,其还不支持安全连接。
必须通过 web 展示来源不一的各种网络内容,但又不能完全使用NSAllowsArbitraryLoadsInWebContent所管理的类。