iOS 9 HTTPS适配

作者: LoveY34 | 来源:发表于2016-08-24 18:08 被阅读10055次

     关于https的简介和说明我都是参考下面的文章:(谢谢文章作者)

    1.http://my.oschina.net/vimfung/blog/494687

    2.http://oncenote.com/2014/10/21/Security-1-HTTPS/ 

    3.http://blog.csdn.net/dachao_me/article/details/48624685?ref=myread

    最新消息:苹果关于接入https的截止时间被延期了,具体截止时间尚未定,苹果推迟https接入截止时间,小伙伴们!别太着急了!

    https的说明我就不多说了,想要了解详细内容查看上面的链接,很多专业名词我也不是很明白,只后悔大学的时候关于网络工程等一些课程没有好好听吧!我写这篇文章主要是为了iOS工程中http转化为https的教程。

    1.修改info.plist中不安全的http兼容配置

               目前绝大多数工作为了解决https的问题,直接在info.plist中添加配置使得系统的请求类NSURLSession(NSURLConnection)默认的请求方式从https转化为http,

    注意:加了这个配置后,http和https都是兼容的,如果是https请求,会继续走https,是http请求会继续走http

    配置如下:

    这种方法只能说治标不治本,再说苹果公司也做出了规定2017年上架的app必须使用https不然可能无法通过审核,所以为了适配https的第一步就是删除这个配置,讲默认请求方式设置成https。删除后再次启动程序会发现请求全部失败,这个错误相信大家都很熟悉,没错就是因为服务器不支持https导致的。

    2.使用系统的NSURLSession(NSURLConnection)或者第三方的请求框架(AFNetworking)实现https适配

          我项目中使用的是AFNetworking 3.1,所以我先利用AFNetworking做适配(其实AFNetworking的https适配还是利用NSURLSession(NSURLConnection)做的适配,只不过NSURLSession(NSURLConnection)适配有点麻烦,AFNetworking的适配更加简单),原本的manager初始化不变,只不过需要为manager的securityPolicy设置值(不好意思哦!不知道怎么样才能添加规范的代码,只能用截图来代替了)。

    添加完成之后还是出现上面的问题:

    检查后发现请求的路径不对,之前都是http,忘记改成https了(请求的路径一定要跟服务器开发人员确定好了),修改完成后还是报错,抓狂!!还是很奇葩的错误,请求被取消了,错误码-999,

    找了很多资料才发现还需要站点证书,上面请求失败可能是因为ssl第一次握手的时候验证没通过,然后就直接被取消了。所以这时候就需要获取站点的证书,获取的方法有两种:

    1.通过openssl命令获取,命令如下(以百度为例):

    openssl s_client -connect www.baidu.com:443 </dev/null 2>/dev/null | openssl x509 -outform DER > https1.cer

    这个命令的目的就是直接在你的终端打开的当前目录下面下载某一站点的证书,但是我怎么都获取不到下载的证书都是空的,而且终端还报错,找不到错误的原因,没办法只能用第二种办法了

    2.直接在浏览器中打开项目的任意一个接口的完整路径,如果你服务器支持https的话会在链接的前面出现一个小锁的图标(我使用的是safair浏览器),点击小锁会出现提示点击显示证书就会出现站点证书的信息了(以百度为例),点击证书的图标到桌面上就可以把证书下载到桌面上了,这样就获取到站点证书了(这种方式不知道会不会存在啥问题,但是到目前为止我没遇到啥问题)

    获取到证书后把证书放到项目的mainbundle中,并用代码获取

    这时候再跑起来,接口都能获取到数据了,成功了,不过到这里大家不知道会不会存在疑问,证书这么容易获取到,那别人获取了怎么办?就算用抓包工具拦截了请求里面的内容都是加密的,但是别人可以利用证书向我们服务器发请求的,是不是也存在点问题呢?这个问题我到现在还不是很明白,有的资料说这样获取的证书是公钥,没有私钥的话也是白费力气。

    3.由于iOS做https适配的时候对服务器是有要求的(一个符合 ATS 要求的 HTTPS),所以出了问题也不一定是客户端的问题

           其实上面成功了,但是还有很多概念不是很清楚,例如啥叫ATS(App Transport Security),它跟https有啥关系呢?

          App Transport Security(简称ATS)特性, 主要使到原来请求的时候用到的HTTP,都转向TLS1.2协议进行传输。这也意味着所有的HTTP协议都强制使用了HTTPS协议进行传输,ATS是在iOS 9.0 和 OS X v10.11版本中增加的特性,使用iOS 9.0或者OS X v10.11的SDK版本(或更新的SDK)进行编译应用时会默认启动ATS。则需要对ATS进行配置。如果使用iOS 9.0或者OS X v10.11之前的SDK版本编译的应用默认是禁止ATS的,因此不会影响应用的网络连接方面的功能(即使在iOS 9.0的机子上跑也是不影响的)。其实ATS并不单单针对HTTP进行了限制,对HTTPS也有一定的要求:

    首先颁发给服务器证书的证书机构(CA)的根证书必须是内置于操作系统(哪些根证书被信任可以查看https://support.apple.com/zh-cn/HT205205,或者在你的机子的设置-通用-关于本机最下面的“进一步了解被信任的证书”中查看,百度的CA根证书:)或者受用户或者系统管理员信任并安装到操作系统上的。而且必须要基于TLS 1.2版本协议(以百度为例,最好使用chrome浏览器,其他的浏览器我没找到查看TSL协议的版本号)。再来就是连接的加密方式要提供Forward Secrecy(FS正向保密,感兴趣的筒子可以看看这个https://vincent.bernat.im/en/blog/2011-ssl-perfect-forward-secrecy.html,--!已经打不开了,支持Forward Secrecy的加密方式

    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

    ),文档中罗列出了支持的加密算法(上面的原文中有说明,我把它独立抽出来放到下面表格中查看)。最后就是证书至少要使用一个SHA256的指纹与任一个2048位或者更高位的RSA密钥,或者是256位或者更高位的ECC密钥。如果不符合其中一项,请求将被中断并返回nil,简单的说就是下面几个要求:

    1.Transport Layer Security协议版本要求TLS1.2以上

    2.服务的Ciphers配置要求支持Forward Secrecy等

    3.证书签名算法符合ATS要求等

    以上就是一次排查服务器的https是否符合ATS规格的方法,当然也可以使用下面的命令行一次性查询:输出结果都是pass的话就说明链接是支持ATS的。

    nscurl --ats-diagnostics --verbose https://www.baidu.com

    4.由于很多第三方的请求尚未适配https,所以iOS的ATS规格又分为四大类

    1.HTTPS Only (只有HTTPS,所有情况下都使用ATS)

    顾名思义,这种情况不需要针对某一个域名或者站点做特殊处理,只要服务器的https符合ATS规格就可以了

    2.Mix & Match(混合)

    这种类型主要某些第三方的请求不支持https或者支持的https不符合ATS的情况:

    2.1 在info.plist中添加这个配置项后,ATS当与这个子域交互的时候撤销了必须使用HTTPS的要求(以友盟为例)

    2.2 当你请求的第三方服务器支持了https,但是不符合ATS规格,例如SSL版本低于1.2或者FS加密不符合要求的时候,可以做如下配置:

    2.3 NSIncludesSubdomains 关键字告诉 App Transport Security 这个“例外”(Exception)适用于这个特定域名的所有子域。这个“例外”(Exception)还进一步通过扩展可接受的密码列表来定义这个域名可以使用不支持forward secrecy( NSExceptionRequiresForwardSecrecy ) 协议的密码。想了解更多关于forward secrecy的信息,推荐去看官方文档 Apple's tech note

    3. Opt Out(禁用ATS)

    这个也是目前做法最广泛的一种方式,把默认的请求的请求方式变成不安全的http,方法上面已经说过了。

    4. Opt Out With Exceptions(除特殊情况外,都不使用ATS)

    当你的应用撤消了App Transport Security,,但同时定义了一些“例外”(Exception),指定了一个或多个“例外”(Exception)来表明哪些是必须要求 App Transport Security的。

    相关文章

      网友评论

      • 宁夏灼雪__:你好,我们服务端开了HTTPS ,我把URL 也都改成HTTPS,但是我手机端的 Allow Arbitrary Loads 还是设置YES 功能照常可以使用啊,会不会有什么影响,比如上架
        LoveY34:设置了Allow Arbitrary Loads就是兼容了http请求
      • SimpleBook_:你好,楼主,适配HTTps的话,是不是之info.plist里用来兼容HTTP请求的那个设置就不能添加了或者设置为NO?(接手的别人的项目,他是在plist里设置了那一项,现在我适配HTTPS)
        LoveY34:就不需要Allow Arbitrary Loads的配置了!但是有些第三方没有做https的需要在这里加https白名单,添加方法文中有提到!
      • TBG:博主,你好, 我有一个项目里使用的是NSURLSession,在didReceiveChallenge回调里验证了证书,info.plist里也设置了<key>NSAppTransportSecurity</key>
        <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
        <key>NSExceptionDomains</key>
        <dict>
        <key>MYSERVER.com</key>
        <dict>
        <key>NSExceptionAllowsInsecureHTTPLoads</key>
        <false/>
        <key>NSIncludesSubdomains</key>
        <true/>
        </dict>
        </dict>
        </dict>

        很奇怪的是,iOS10的设备访问是没问题的,iOS9死活报-1004。。。求解。。
        cf9fa8a5d374:@TBG 这个解决了吗
      • b9ea8ac47824:对于自认证的方式,我只需要向服务器询问cer证书,然后导入客户端,进行认证就可以了吗?找了很多资料,对于ssl什么的讲解头都看炸了。
      • 呵呵哈嘻:大神 新年快乐
        请教一下 我这边用的是收费的证书 就是只把http改成https就能用的那种
        在10+系统上一切正常
        但是在9系统上就返回错误码 -999
        问题也排查到了 就是- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
        forDomain:(NSString *)domain 这个方法返回NO
        这是没验证证书的问题吗?那是不是我要去判断版本 要是9的话还要加上验证证书的部分?
        cf9fa8a5d374:@呵呵哈嘻 这个解决了吗
      • cyril_:请问一下,服务器端同事说他们搞定,我在客户端只是去掉了 NSAllowsArbitraryLoads 这个字段 ,然后把Http改成Https,就直接能用了,AF我还没设置securityPolicy呢,怎么就能用了呢,这是为什么,楼主知道怎么个情况吗
        LoveY34:@cyril_ 数据都请求得到是吧?那你的证书可能是单项验证的!主要让服务器做验证,你看看上面的评论就知道了!要是双向验证的话可能需要客户端绑证书!
      • 在没老之前:楼主,你好。我的Allow Arbitrary Loads设置为YES,然后域名是https,运行APP,一切正常。
        然后我想把Allow Arbitrary Loads设置为NO,域名同样是https,运行APP,也是一切正常,但是控制台会报警告。
        所以我想问,我的代码应该怎么改,info.plist里面怎么改
        我们的证书是买的那种比较正规的证书
        LoveY34:@在没老之前 如果苹果审核要求https的话,你这样估计不行,苹果本来不是把https适配的截止日期设定在2017年1月1号嘛!现在好像推迟了:http://www.cocoachina.com/apple/20161223/18431.html,最新的截止时间还没有出来呢!
        然后就是你的警告,你的请求好像不是https的吧?是不是有第三方的请求或者图片下载地址不是https的?
        在没老之前:@lovey1314 如果我设置为NO的话,就打印这种:App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.

        我想知道,如果我把Allow Arbitrary Loads设置为YES,然后不做其他任何修改。但是域名是https的。我提交给苹果,审核能过吗?
        LoveY34:@在没老之前 Allow Arbitrary Loads设置为YES代表app是兼容https和http的,设置为NO的话或者在info.plist不加这个配置项使用默认配置的话只支持https了。然后你说的控制台警告是什么内容?
      • eAssh:服务器端已经改成了HTTPS,NSAppTransportSecurity配置删除启动后,也可以正常的调用接口,这种情况下面的步骤还要再做吗
        LoveY34:@一碗方便面 数据请求都没问题吗?你可以抓包看看请求内容是否加密过!可能你们的https属于单向验证的,客户端需要做的工作比较少,至于详细情况还需要了解下https/http的知识。
      • Mr大喵喵:An SSL error has occurred and a secure connection to the server cannot be made.
        博主有遇到这个问题吗?这是什么原因,都按照你的配了,请求失败,返回这个。
        LoveY34:@你嘴角上扬的酒窝 是不是还是证书添加的有问题啊?错误直译的话就是加密连接失败了!是不是证书验证没通过啊?
      • 忙碌的小码畜:博主的这个方法是双向https的验证,所以客户端需要一个验证证书。如果是单向的客户端就不需要证书了,所以呢,在改动之前要和服务端的人员问清楚服务器的验证是单向的还是双向。
        LoveY34:@叫什么昵称呢 还有这个区分呢?我当初做的时候没注意!反正在没加证书前请求是不通的!所以之后就额外加了证书才可以的!
      • 画眼线的乞丐:博主您好 按您写的当然没有问题,但是不知你有没有发现,直接将域名改成https的,然后去掉App Transport Security Settings就能返回成功呢 :grin:
        LoveY34:@画眼线的乞丐 你没加证书嘛?那可能就像楼上的小伙伴说的,属于单向验证,不需要配置证书,只有双向验证才需要客户端配置证书,具体是双向还是单向需要问你们服务器开发人员了!
      • ITLikeyi:大神你好 我按照你说的 可是 证书路径为nil
        LoveY34:😂额!你这个有点复杂啊!我访问服务器的环境用的是域名的,然后为请求配上证书就好了!首先不管数据是否为空,接口通了就好了,数据这块需要跟服务器联调。你可以在浏览器上调试你的一些不需要登陆的接口,因为浏览器会自动帮你下载安装证书。
        ITLikeyi:@lovey1314 谢谢你的回复, 现在我好迷茫。 因为 我们公司的服务器证书刚升到tsl1.2 然后是SSL证书,并且在苹果官网那个“信任证书”列表里能找到颁发机构的名字。 我不知道我这样是否还要做AFN的证书验证代码。 我现在有2个版本: 1. 一个是什么代码都不改,只是 把访问的接口http改成了https(我们项目域名是IP的:http://132.11.xx.xx,服务器升级后就不是IP访问了) 但是会报错NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9806)
        2. 加了AFN证书验证的代码 访问接口还是IP的 报错还是NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9806)

        报这个错误的前提是 我接口域名 还是用IP域名。 而当我改用服务器给的域名 打个比方https://ebus.car.cn 这样的域名时 会出大问题, 直接导致数据为空的错误提示了。

        我现在不知道怎么下手了。 我想问 域名 还用IP的是否可行,可行的话 报那个错误是怎么回事。 我说的可能有点多,大神有空就帮忙看看,跪谢。
        LoveY34:@ITLikeyi 证书的添加方式和文件添加的方式一样!你可以看看被加入的证书是不是在工程目录里面!还有一个验证的办法就是使用模拟器!打印出证书路径,然后看看路径是否正确!
      • Oooh:你好,1.1以后AppStore上已上线的应用也必须要支持https吗?
        LoveY34:@Oooh 最直接的结果就是拒绝你上架app喽!当然如果你用的企业级账号就不用顾忌这些了!
        Oooh:@lovey1314 意思就是必须要支持啊。。不支持的话会有什么后果。
        LoveY34:@Oooh https://techcrunch.com/2016/06/14/apple-will-require-https-connections-for-ios-apps-by-the-end-of-2016/和http://www.cocoachina.com/apple/20160621/16778.html里面有提到,你可以看看
      • 萨达搜索到:有个疑问,头像的url也需要这么搞吗?(第三方登录获取的头像 我无法控制他们是http还是https,是需要每个都加白名单吗)
        LoveY34:@紫霞大仙F 额!app内部也是通过NSURLSession利用第三方头像url下载头像图片的,而NSURLSession默认也是https请求的,所以如果第三方头像url是http的话,可能下载不了,需要加入白名单。当然你可以试试!
      • 萨达搜索到:你好,第三方返回的头像url 不是http开头的 应该没关系吧
      • 子书不言:为什么我工程里取不到.cer的文件 :joy:
        子书不言:@LoveY34 手动添加一遍,拖进去时实际没有引用
        ITLikeyi:@子书不言 你好, 请问你这个问题怎么解决的
        LoveY34:@子书不言 看看你的代码!咋取的?
      • d1bed0b7de6a:问下作者,.crt和.key如何转成.cer文件呢?
        LoveY34:我使用的时候证书是按照文中的方法在浏览器中获取到证书文件的,所以.crt和.key如何转成.cer文件我也没试过,不过你可以试试楼上的方法,要还是不行就只能百度或者Google了!
        371e24088d09:@zliuqing 我们需要的是.cer的证书。但是后台可能给我们的是.crt的证书。我们需要转换一下:打开终端 -> cd到.crt证书路径 -> 输入openssl x509 -in 你的证书.crt -out 你的证书.cer -outform der,证书就准备好了
      • 暴走的西瓜:code=999.按照上面说的抓取站点证书还是不行

        LoveY34:@暴走的西瓜 配置证书的代码添加的对不对啊?
      • 2a392233fc62:博主我想问一下,Exception Domains是只针对特例域名吗?如果是IP地址管用吗?我把域名加入到Exception Domains中属性也设置了,但是只能把文字加载出来图片加载不出来,不知道是为什么?
        LoveY34:@noaicooder 我在Exception Domains里面加的都是域名!Ip地址加了好像没用!图片打不开的话,你先试试把图片的地址放到浏览器里面看看能不能下载,能下载的说说明图片的地址可能被ATS屏蔽了,需要针对图片的域名处理下!要是在浏览器里下载不了或者打不开的话只能说明你的图片地址有问题了!
      • 牧童s:服务器买了别人的,说是改成https了,客户端将Allow Arbitrary Loads改为NO?有的网页是http,就得添加白名单?服务端说服务器配置好了,不用添加证书秘钥什么的,对吗?
        LoveY34:@牧童s 好像是这样的!不是https的话只能加到白名单里了!或者从app内部跳转到浏览器里打开!
        牧童s:@lovey1314 谢谢,我这边属于上述(混合)情况,但我没有添加证书,也可以跑得通,没有报错。有一个疑问就是,webview的加载链接也必须支持https?那么其他跳转链接呢?
        LoveY34:@牧童s
        1.需不需要加白名单,你可以先试试不加,请求不同的话再加上就是了!
        2.证书的话是需要的!服务器要是没给你的话!可以在浏览器中打开获取到证书,方法在文章中说了
      • xxxixxxx:不知道为什么还是 Domain=NSURLErrorDomain Code=-1004 "Could not connect to the server."
        LoveY34:@拾荒少年v 你现在浏览器里面打开你们服务器的地址,看看有没有啥问题,问题出在服务器上的可能性比较大
      • 12f2e73a845d:2017. 01.01 苹果可能就要强制执行 https的地址可以说一下吗?我看一下官方的说法
        LoveY34:@Adam_Davies https://techcrunch.com/2016/06/14/apple-will-require-https-connections-for-ios-apps-by-the-end-of-2016/
        LoveY34:@Adam_Davies http://www.cocoachina.com/apple/20160621/16778.html
        LoveY34:@Adam_Davies 我也是在网上找的资料,官方好像也没具体说明吧!
      • love断鸿:2017. 01.01 苹果可能就要强制执行 https了, 这篇文章写得很详细 很好, 但是我有些地方不懂 , 如果一旦在请求的时候出问题了 怎么排查是前端还是服务器的问题?
        LoveY34:@love断鸿 额!苹果针对https的审核要求到17年年初才实施!你先也用不着急啊!可以在这段时间内完成对https的适配啊!
        love断鸿:@lovey1314 现在真的蛋疼, 服务端不用https 前端直接降http以后会被拒,只能用追加特例配置的方法
        LoveY34:@love断鸿 额!首先客户端的配置证书的代码要添加正确了(代码基本就那么多),然后是SSL证书(可以在浏览器中打开链接查看证书的正确性,一般请求直接报-999的话一般都是证书问题),同时还要确保域名支持https,不支持的话需要在info.plist中针对该域名追加特例配置。客户端基本就这么多了!要是还出问题的话可能是服务器问题,具体情况需要联调才能知道

      本文标题:iOS 9 HTTPS适配

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