美文网首页iOS 实用技术iOS开发技巧优化
iOS 升级HTTPS通过ATS你所要知道的

iOS 升级HTTPS通过ATS你所要知道的

作者: 床前明月_光 | 来源:发表于2016-12-02 11:00 被阅读13447次

由于苹果规定2017年1月1日以后,所有APP都要使用HTTPS进行网络请求,否则无法上架,因此研究了一下在iOS中使用HTTPS请求的实现。网上搜索了一些比较有用资料,大家可以参考下

苹果强制升级的HTTPS不仅仅是在接口HTTP上加个S那么简单:
它所有满足的是iOS9中新增App Transport Security(简称ATS)特性:
那满足ATS我们需要做什么呢
1.必须是苹果信任的CA证书机构颁发的证书
2.后台传输协议必须满足: TLS1.2 (这很重要, 后面的自制证书满足这个条件是前提)
3.签字算法只能是下面的一种:

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

4.证书必须使用SHA256或者更好的哈希算法进行签名,要么是2048位或者更长的RSA密钥,要么就是256位或更长的ECC密钥。

目前有两种升级到HTTPS得方法:
1.第三方认证的颁发CA证书(推荐)
2.自己制作证书(这种不知道能不能满足苹果的审核)

一: 第三方认证的颁发CA证书

证书到底长什么样子呢? 取个栗子:
大家请打开https://www.baidu.com
然后看到

百度的证书分析百度的证书分析
那些证书机构颁发的证书能用:苹果官方信任证书

收费SSL证书: 网上百度一大把, 收费还挺贵的,自己可以多找几个对比一下
免费SSL证书: 除了收费的CA证书机构, 你还可以去腾讯云申请免费的SSL证书, 教程免费在腾讯云申请SSL证书的方法
沃通(WoSign)免费的SSL证书最近被苹果封杀了, 能不能用大家可以看一下苹果的公告: 您的苹果手机轻点“设置”>“通用”>“关于本机”>"证书信任设置">"进一步了解被信任的证书"去了解

检测你的接口是否满足苹果的ATS要求, 有以下两种方法:

1.腾讯云提供的检测页面检测

腾讯云的检测页面腾讯云的检测页面
2 终端输入 nsurl --ats-diagnostics --verbose 你的接口地址
大家可以参考这篇文章,里面的说的很明白:
关于iOS9中的App Transport Security相关说明及适配(更新于2016.7.1)
里面会详细说明你的证书哪点不符合ATS要求
当然下面自己制作证书去实现HTTPS的,检测不通过的,所以我觉得审核会被拒
这种方法配置好了, 在手机端就什么都不用配置就可以请求了

二: 自己制作证书

苹果官方信任证书里说到有三种证书:

1 可信的根证书用于建立信任链,以验证由可信的根签署的其他证书,例如,与 Web 服务器建立安全连接。当 IT 管理员创建 iPhone、iPad 或 iPod touch 的配置描述文件时,无需提供这些可信的根证书。
2 始终询问的证书不受信任,但不受阻止。使用其中一个证书时,系统将提示您选择是否信任该证书。
3 已阻止的证书视为被盗用,将不再受信任。

自制证书我觉得应该就是属于第二种情况, 所以这种方法我也不知道能不能通过苹果的审核, 只是提供一个方法给大家参考, 看到网上有人说可以,有人说不可以, 不到1月1号,自己没试过都不敢说大话
这种方式拿到后台的接口用谷歌浏览器打开跟百度的证书是有区别的

自己制作证书自己制作证书
很明显没有绿锁, 当打开的时候会询问是否连接这个不受信任的连接才会进一步打开, 下面就来一步步的实现(包括怎么制作证书)
iOS使用自签名证书实现HTTPS请求
iOS Https协议 自签证书访问数据参考这个例子的时候,博主自带的Demo AFN框架请求不了数据, 我用了最新AFN版本的成功返回数据
还可以参考一下
iOS 10 适配 ATS app支持https通过App Store审核

我在利用原生的代码测试时遇到的问题

@interface ViewController () <NSURLSessionDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
   
   
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    
   NSURLSessionDataTask *task =  [session dataTaskWithURL:[NSURL URLWithString:@"https://www.baidu.com"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    }];
   [task resume];
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
    NSLog(@"接收到服务器响应");
    //注意:这里需要使用completionHandler回调告诉系统应该如何处理服务器返回的数据
    //默认是取消
    /**
     NSURLSessionResponseCancel = 0,            默认的处理方式,取消
     NSURLSessionResponseAllow = 1,             接收服务器返回的数据
     NSURLSessionResponseBecomeDownload = 2,    变成一个下载请求
     NSURLSessionResponseBecomeStream           变成一个流
     */
    completionHandler(NSURLSessionResponseAllow);
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data {
    NSLog(@"获取到服务段数据");
    NSLog(@"%@",[self jsonToDictionary:data]);
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error {
    NSLog(@"请求完成%@", error);
}

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler {
    NSLog(@"证书认证");
    if ([[[challenge protectionSpace] authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust]) {
        do
        {
            SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
            NSCAssert(serverTrust != nil, @"serverTrust is nil");
            if(nil == serverTrust)
                break; /* failed */
            /**
             *  导入多张CA证书(Certification Authority,支持SSL证书以及自签名的CA),请替换掉你的证书名称
             */
            NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"ca" ofType:@"cer"];//自签名证书
            NSData* caCert = [NSData dataWithContentsOfFile:cerPath];

            NSCAssert(caCert != nil, @"caCert is nil");
            if(nil == caCert)
                break; /* failed */
            
            SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert);
            NSCAssert(caRef != nil, @"caRef is nil");
            if(nil == caRef)
                break; /* failed */
            
            //可以添加多张证书
            NSArray *caArray = @[(__bridge id)(caRef)];
            
            NSCAssert(caArray != nil, @"caArray is nil");
            if(nil == caArray)
                break; /* failed */
            
            //将读取的证书设置为服务端帧数的根证书
            OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);
            NSCAssert(errSecSuccess == status, @"SecTrustSetAnchorCertificates failed");
            if(!(errSecSuccess == status))
                break; /* failed */
            
            SecTrustResultType result = -1;
            //通过本地导入的证书来验证服务器的证书是否可信
            status = SecTrustEvaluate(serverTrust, &result);
            if(!(errSecSuccess == status))
                break; /* failed */
            NSLog(@"stutas:%d",(int)status);
            NSLog(@"Result: %d", result);
            
            BOOL allowConnect = (result == kSecTrustResultUnspecified) || (result == kSecTrustResultProceed);
            if (allowConnect) {
                NSLog(@"success");
            }else {
                NSLog(@"error");
            }

            /* kSecTrustResultUnspecified and kSecTrustResultProceed are success */
            if(! allowConnect)
            {
                break; /* failed */
            }
            
#if 0
            /* Treat kSecTrustResultConfirm and kSecTrustResultRecoverableTrustFailure as success */
            /*   since the user will likely tap-through to see the dancing bunnies */
            if(result == kSecTrustResultDeny || result == kSecTrustResultFatalTrustFailure || result == kSecTrustResultOtherError)
                break; /* failed to trust cert (good in this case) */
#endif
            
            // The only good exit point
            NSLog(@"信任该证书");
            
            NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
            return [[challenge sender] useCredential: credential
                          forAuthenticationChallenge: challenge];
            
        }
        while(0);
    }
    
    // Bad dog
    NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
    completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge,credential);
    return [[challenge sender] cancelAuthenticationChallenge: challenge];
}

- (NSDictionary *)jsonToDictionary:(NSData *)jsonData {
    NSError *jsonError;
    NSDictionary *resultDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:&jsonError];
    return resultDic;
}

@end

下面说说我在配置自己制作证书过程中遇到的问题:
1.转换证书: 把后台给你的.crt证书转化为.cer后缀
终端命令行openssl x509 -in 你的证书.crt -out 你的证书.cer -outform der

2.利用系统的方法来不到- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler { NSLog(@"证书认证"); }这个方法的时候, 是因为后台的传输协议还没升级到TLS1.2, 叫后台升级后就可以来到验证证书的这个方法了.

3.拖入证书读取不出证书数据
参考: https的证书错误,错误码-1012问题及解决方案

SDWebImage: 项目中大家用到AFN请求网络数据, 升级验证SSL证书的方案相信你看完上面的参考文章已经没问题了, 我给出的代码, 自定义网络请求也没问题了, 还有就是SDWebImage框架的请求HTTPS的图片时,大家可以绕过证书验证去加载图片[imageView sd_setImageWithURL:[NSURL URLWithString:urlString] placeholderImage:self.placeholder options:SDWebImageAllowInvalidSSLCertificates];

恩, 这就是这几天升级HTTPS觉得有帮助的参考和总结.希望帮到你

相关文章

网友评论

  • yanhooIT:"nsurl --ats-diagnostics --verbose 你的接口地址"应该为nscurl
  • CJFeng:你好作者,想问一下,苹果对于白名单有没有数量的限制,我项目里面图片还是http,webView是http,统计上报的也是http,配的白名单数量偏多,担心审核被拒啊?
  • KuKuMan:苹果并没这样规定,使误读了,不过文章借鉴了:heart_eyes:
  • nenhall:不错,写的很详细
  • fc18f69e6ff0:如果只有接口实行https 接口中的图片地址还是http的 web跳转地址也是http的 怎么处理呢?
  • APP叫我取个帅气的昵称:1.1号之后如果没适配HTTPS 苹果会把已经上线的APP下架吗
    APP叫我取个帅气的昵称:@绿血贵族 好的,谢谢
    安浪创想: @APP叫我取个帅气的昵称 应该不会,那么多app,要是都下架了,手机用户还不把苹果骂死。只是之后不能上新品吧😄
  • 56b74f2b44fa:你好作者,想问一下,IOS10,Facebook,Twitter,微信,微博等配置好白名单,NSAllowsArbitraryLoads 值为NO,能正常使用这些三方的登录和分享功能,是不是这些三方就通过了苹果的ATS校验了?
    床前明月_光:@鱼者渔也 据我了解, 你说的情况不是通过了苹果的ATS机制, 只是苹果目前允许这样子配置让你通过审核和进行第三方的接口访问
  • Rchongg:请注意 白名单不能屏蔽IP,只能是域名!
    床前明月_光:@Rchongg 谢谢提醒
  • HenryM:升级到https之后,现在线上版本还是http,会导致线上版本拿不到数据吗?
    94f9118b0c81:@maliao 您好,请问你这个怎么改变端口,我的情况是客户端都是发https,但是线上可能服务器没升级,还是不支持https的.
    HenryM:@床前明月_光 搞定了,改变端口就行了
    床前明月_光:@maliao 这方面还没求证哦, 不过个人觉得还是尽早升级比较好.
  • 大刀阔斧007:看了你推荐的文章中,有个说自签名证书通不过审核,但你下面介绍的第二种方式就是自签名啊
    大刀阔斧007:@床前明月_光 好的
    床前明月_光:@小不点爱抽烟 是啊,所以我在文章也说这种有可能不通过有可能通过, 我搜集的资料两种说法都有,.所以还是建议你去第三方申请一个苹果信任的比较好,免费得也有.
  • GaryHuang:你好 我是基于webview的html开发的 app 加载webview只是一个http://.......的接口 这个需要做将http该车https??
    安浪创想: @上善_若水 当然
    GaryHuang:@床前明月_光 谢谢的 刚看了 :smile:
    床前明月_光:@上善_若水 [iOS 10 适配 ATS app支持https通过App Store审核](http://www.jianshu.com/p/36ddc5b009a7) 建议你看一下这篇,多了解一下
  • 陈怀哲:例如:现在我们的接口是http://api.mycompany.com/user/login?uid=xxxxxxxxxx,升级https之后,是不是需要后台做升级,而app这边只需要把接口改成https://api.mycompany.com/user/login?uid=xxxxxxxxxx就可以了,目前app端用的是基于AFN的一个框架
    http://www.jianshu.com/p/c7266337d834
    床前明月_光:@陈怀哲 这个肯定的,如果后台把SSL证书配置好,给你的接口肯定是 `https://域名:443` 这样的
    陈怀哲:@床前明月_光 好的,那网络接口要改成https前缀吗
    床前明月_光:@陈怀哲 你所用到的基于AFN封装框架应该不会影响你的网络请求, 不过最好把AFN升级一下
  • 863c73f31933:你好作者,在2017年1月1日之后App中还含有HTTP链接的App还能不能用呢,还有会不会被强制下架?
    床前明月_光:@SunlightInMyLif 这个就不知道了, 你如果知道,请跟我说一声.
    863c73f31933:@床前明月_光 要是到时候我没提交新版本app,App Store上还是支持http的会有什么影响不?
    床前明月_光:@SunlightInMyLif 如果是自己的服务器接口,会被拒,如果是AV框架,和Webkit 用到的接口是HTTP 暂时还可以,第三方接口设置白名单也还可以支持HTTP
  • 罗火火:楼楼能不能留个联系方式 想请教一下这个
    床前明月_光:@不高不帅不体贴 QQ:874020188
  • Python数据分析实战:如果后台做升级,App 只需要换个接口名字吗?其他的要不要改?第三方怎么处理,例如:友盟,sharesdk ,afn,MJ 刷新等
    床前明月_光:@SilenceYaung 第三方如果还没升级到HTTPS的话,可以通过白名单的方式暂时用HTTP。
  • mark666:没看明白,app需要怎么去适配?
    床前明月_光:@mark666 如果你是基于第一种方式,把AFN 升级到最新,什么都不用做
    mark666:@床前明月_光 那以前基于AFNetworking 的网络请求要做什么样的适配?
    床前明月_光:@mark666 主要还是后台,升级HTTPS 需要SSL 证书。假如是我文章中的第一种方案,手机端不用做任何操作

本文标题:iOS 升级HTTPS通过ATS你所要知道的

本文链接:https://www.haomeiwen.com/subject/pmoxmttx.html