ios认证书_ios 证书信任设置

ios认证书_ios 证书信任设置调用NSURLConnection实现HTTPS访问时,如果服务器证书是由CA机构颁发的(全球可信的机构,如verisign),连接方式和HTTP并没有区别。但是如果证书不是合法机构颁发的就需要定制证书验证过程。本文从记录了部分对于该过程的研究。

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

0x00 问题引出


   调用NSURLConnection实现HTTPS访问时,如果服务器证书是由CA机构颁发的(全球可信的机构,如verisign),连接方式和HTTP并没有区别。代码如下:

 

      
NSString *urlStr = @"https://yourURL";
NSURL *url = [NSURL URLWithString:urlStr];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

    系统会帮你建立TLS连接,验证服务器证书(包含是否过期,证书和访问域名是否一致,证书是否为合法机构颁发等),交换对称加密密钥等,几乎不用自己写任何代码。

 

 

0x01 ATS

    但是iOS9有一个新特性ATS(App Transport Security),需要我们注意一下,在测试访问百度时发现报错:

    NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)


    错误代码定义详解见文件<Security/SecureTranspot.h>,所有相关的错误代码都定义在这个头文件里面。查阅后发现-9802描述为Fatal alert。常见的还有:-9843(域名和证书不符),-9814(证书链中有过期证书)等。

 

    同样的代码在iOS9以前的系统上就不存在问题,这是因为在iOS9之后,ATS默认打开,然后它要求所有网络请求都为HTTPS,且支持TLS V1.2,对加密方式和证书的签名算法强度均有要求(详情见,iOS  App Transport Security研究)。官方文档是这样描述的:

Certificates must be signed with one of the following types of keys:

  • Secure Hash Algorithm 2 (SHA-2) key with a digest length of at least 256 (that is, SHA-256 or greater)
  • Elliptic-Curve Cryptography (ECC) key with a size of at least 256 bits
  • Rivest-Shamir-Adleman (RSA) key with a length of at least 2048 bits
    An invalid certificate results in a hard failure and no connection.

 

    也就是说不满足条件的证书,ATS都会拒绝连接,百度证书如下图。由于它采用的sha1,不满足要求,因此会报错。

计算机生成了可选文字:40 a6 35 7e 83 67 do Ib sha1RSA shal VeriSign 3 Secure 2015F5Ê27E 2015*12Ê29E •.baidu.com. service oper.„

 ios认证书_ios 证书信任设置


    在info.plist文件中加入以下代码,可以关闭ATS,就不会报错了。

 

      
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
 

ios认证书_ios 证书信任设置


    需要注意的是加入以上代码之后会完全关闭ATS,也就是说iOS系统不再检查你的TLS连接的安全性。如果还是需要保留此特性,可以设置NSExceptionDomains属性,指定某个域名,ATS不进行安全检查。按照如下配置也可以通过,可以更加细粒度的管理(详情见,iOS  App Transport Security研究)。

计算机生成了可选文字:App Transport Security Settings 'Exception Domains baidu.com NS ExceptionRequiresForwardSecrecy NS ExceptionAIIowsIn secureHTTPLoads NS IncludesSubdomains Dictionary Dictionary Dictionary Boolean Boolean Boolean (1 item) (1 item) (3 items) YES

 ios认证书_ios 证书信任设置


0x02 自定义证书验证


    为了更深入的了解证书验证过程,动手自定义证书验证过程,如果证书不是向可信CA机构购买的,而是自己做的证书(比如12306,顺便吐槽一下,最近帮同事买票,验证码真心醉了。。。言归正传,正如12306官网所说,为保障您顺畅购票,请下载安装根证书),就必须订制证书验证过程。订制证书验证过程需要实现协议NSURLConnectionDelegate,并实现其中的方法willSendRequestForAuthenticationChallenge,与之相关的还有canAuthenticateAgainstProtectionSpacedidReceiveAuthenticationChallenge,但是如果实现了willSendRequestForAuthenticationChallenge系统就不会调用后两个方法了,本例调用的前者。上代码:

 

      
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
// 1.判断本次鉴别挑战的类型,NSURLAuthenticationMethodServerTrust是验证服务器身份
if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
// 判断如果失败次数大于5次,则不再验证。直接返回失败。
if(challenge.previousFailureCount < 5) {
// 获取信任管理对象,里面包含了待验证的证书,和自定义的策略
SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
// 2.保存验证结果
SecTrustResultType result;
// 注意:该方法是验证证书的关键方法,该方法可能会从网络获取证书,因此不能放在主线程。
// 也可以调用它的异步方法SecTrustEvaluateAsync
SecTrustEvaluate(self.serverTrust, &result);
 
if(result == kSecTrustResultProceed ||
result == kSecTrustResultUnspecified
) {
// 3.以下两种方法调用两个都可以,调用一个就可以了
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
// [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
} else if (result == kSecTrustResultRecoverableTrustFailure) {
// 域名和证书中的不匹配,或者证书过期等
// 中断本次连接
[challenge.sender cancelAuthenticationChallenge:challenge];
[connection cancel];
}
else {
// 域名和证书中的不匹配,或者证书过期等
// 中断本次连接
[challenge.sender cancelAuthenticationChallenge:challenge];
[connection cancel];
}
}
}
}

接下来深入介绍一下整个过程:

 

1.NSURLAuthenticationChallenge


    NSURLAuthenticationChallenge是一个认证挑战类,服务器向客户端发起挑战,要求客户端提供一个挑战凭证NSURLCredential(用户名密码、客户端证书等信息)来接受挑战。如函数:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]就是用SecTrustRef类创建一个挑战凭证。NSURLAuthenticationChallenge中的protectionSpace中保存了挑战相关的信息(如服务器提供的证书,主机名,端口号,协议等),由于willSendRequestForAuthenticationChallenge回调时不止HTTPS服务器身份鉴别,如BasicDigestHTML Form等方式的身份鉴别也会调用该方法,我们关注的是HTTPS证书验证,因此首先判断一下身份鉴别的类型。通过challenge.protectionSpace.authenticationMethod可以获取,可能获取到以下值:

NSURLAuthenticationMethodDefault // 使用默认的身份鉴别方法,默认为Basic方式
NSURLAuthenticationMethodHTTPBasic // 同上
NSURLAuthenticationMethodHTTPDigest // 使用Digest鉴别方式
NSURLAuthenticationMethodHTMLForm // HTML表单方式
NSURLAuthenticationMethodNegotiate
NSURLAuthenticationMethodNTLM
NSURLAuthenticationMethodClientCertificate // 用客户端提供的证书来完成身份鉴别
NSURLAuthenticationMethodServerTrust // 验证服务器证书,该方法主要用于SLLTLS连接的建立。


2.SecTrustEvaluate

函数定义:
OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType * __nullable result)
 
返回值:
OSStatus     定义在SecBase.h0是无错误。


参数:
Trust           信任管理对象,里面包含了待验证的证书,和自定义的策略。
Result          验证结果,有以下情况:

  • kSecTrustResultUnspecified 证书验证成功,但是用户没有明确指出信任此证书。这是最常见的返回值。
  • kSecTrustResultProceed 用户选择信任此证书。
  • kSecTrustResultDeny 用户选择不信任次证书。
  • kSecTrustResultRecoverableTrustFailure 证书不可信,但是经过较小的改动可以修复问题,例如忽略过期证书、增加信任链节点等。在iOS中通常会拒绝该证书,但是收到信息时证书未过期可以通过验证,因此可以验证证书在收到信息时是否过期。
  • kSecTrustResultConfirm 用户预先选择了证书链中得某一个证书在每次使用前询问允许。这个返回值已经不再使用,只在老版本的OS X中使用。

 
    该函数评估证书的有效性用于在数字签名、建立SSL连接等情况。在调用函数前,可以调用SecTrustSetVerifyDate来设置用于验证证书的时间,默认是当前的时间。如果证书是自定义的,则需要在调用SecTrustEvaluate之前,自己构造证书链等信息。
   
    如果信任管理对象(trust management object)中缺少验证页证书的上一级证书,它会在以下位置搜索证书:

    1.调用者自定义的证书链(SecTrustSetKeychains
    2.通过SecTrustSetAnchorCertificates设置的证书
    3.系统的证书链
    4.从网络获取

    注意:
该函数在调用时可能涉及到网络请求,因此不能在主线程调用,可以调用它的异步方法SecTrustEvaluateAsync

 


3.响应挑战


   
 证书验证完成后,会根据验证结果响应服务器挑战,响应挑战必须调用NSURLAuthenticationChallenge里的sender发送NSURLAuthenTicationChallengeSender定义了身份鉴别用的sender必须实现的协议,不同的方法提供不同的响应方式。注意,在调用其中一种响应方式后,之后再调用无效,同时,willSendRequestForAuthenticationChallenge
里必须调用一种响应挑战的方式。协议里定义的方法如下:

 

    
    
    
// 取消挑战。如果证书验证不通过,调用该方法终止本次认证。
- (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
// 响应挑战。如果是服务器和客户端的单向验证,服务器不需要验证客户端的证书,因此调用该方法即可。
-(void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *) challenge
// 用凭证响应挑战。如果是双向验证,不仅客户端要验证服务器身份,服务器也需要客户端提供证书,因此需要提供凭证
-(void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge

0x03 总结:


   由于公司云端使用的HTTPS,与之通信时要使用HTTPS协议,于是开始研究相关的内容,发现网上相关的资料太少,自己动手做了很多实验,查阅了很多文档终于把问题梳理清楚,还有很多疏漏或者错误的地方,欢迎大家指正。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/189184.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Mysql增删改查sql语句练习

    Mysql增删改查sql语句练习关于数据库的一些操作:进入mysql命令行:mysql-uroot–p查看所有数据库:showdatabases;创建数据库:createdatabasewgcharsetutf8;删除数据库:dropdatabasewg;选择数据库:usedatabases;查看所有表:showtables;查看创建数据库的语句…

  • pandas之分组groupby()的使用整理与总结

    pandas之分组groupby()的使用整理与总结前言在使用pandas的时候,有些场景需要对数据内部进行分组处理,如一组全校学生成绩的数据,我们想通过班级进行分组,或者再对班级分组后的性别进行分组来进行分析,这时通过pandas下的groupby()函数就可以解决。在使用pandas进行数据分析时,groupby()函数将会是一个数据分析辅助的利器。groupby的作用可以参考超好用的pandas之groupby中作者的插图进行直…

  • 零基础成为黑客[通俗易懂]

    零基础成为黑客[通俗易懂]笔者刚乱入了CTF,算是入门了,此处分享一下入门经验一个漏洞练习平台:https://github.com/gh0stkey/DoraBox使用教程参考:https://www.cnblogs.com/zhaijiahui/p/10789251.html攻防世界:https://adworld.xctf.org.cn/task这个网站很良心,第一次点开这个网站,仿佛看到了新世界…

  • java arraylist遍历_java 遍历arrayList的四种方法

    java arraylist遍历_java 遍历arrayList的四种方法importjava.util.ArrayList;importjava.util.Iterator;importjava.util.List;publicclassArrayListDemo{publicstaticvoidmain(Stringargs[]){Listlist=newArrayList();list.add(“luojiahui”);list.add(“…

  • sql注入orderby子句的功能_sql order by

    sql注入orderby子句的功能_sql order byuniqueidentifier全局唯一标识符(GUID)。注释uniqueidentifier数据类型的列或局部变量可用两种方法初始化为一个值:使用NEWID函数。将字符串常量转换为如下形式(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,其中

    2022年10月31日
  • java反射原理简单介绍(java反射机制的应用)

    前面给大家介绍了一下什么是java反射机制,那么下面要给大家介绍的就是java反射机制的原理,那么它的原理究竟是怎样的呢?下面就通过下面来做一下详细的了解吧。首先我们再来介绍一下java反射机制。java反射机制就是java程序在运行的时候动态的创建类并调用类的方法以及属性。下面就来介绍一下原理。一、java反射机制原理下面是我们经常可以见到的反射例子:Class>clz=Class….

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号