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)
blank

相关推荐

  • 数据库查询优化——Mysql索引

    数据库查询优化——Mysql索引

    2020年11月12日
  • python抛出异常会终止程序吗_catch里面抛出异常

    python抛出异常会终止程序吗_catch里面抛出异常Python抛出异常

    2022年10月18日
  • java删除数组中指定元素_java学习中如何删除数组中的指定元素「建议收藏」

    java删除数组中指定元素_java学习中如何删除数组中的指定元素「建议收藏」java的api中,并没有提供删除数组中元素的方法。虽然数组是一个对象,不过并没有提供add()remove()或查找元素的方法。这就是为什么类似ArrayList和HashSet受欢迎的原因。不过,我们要感谢ApacheCommonsUtils,我们可以使用这个库的ArrayUtils类来轻易的删除数组中的元素。不过有一点需要注意,数组是在大小是固定的,这意味这我们删除元素后,并不会减少数组的…

  • tomcat7编译

    tomcat7编译本文是Tomcat源代码阅读系列的第一篇文章,在阅读Tomcat源代码之前,我们首先需要将Tomcat的源代码在IDE里面运行起来,这样方便我们阅读的过程中调试。本文总结一下在IDEA或者Eclipse中运行Tomcat源代码环境的搭建过程,同时我们通过Maven来负责项目的构建。在进行搭建之前,我们首先来说一下总体的思路。我们知道Tomcat运行的时候,一部分是源代码编译以后的可运行

  • navicat注册激活[最新免费获取]

    (navicat注册激活)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

  • NPOI导出Excel2007

    NPOI导出Excel2007publicvoidExport_ProjectList(DataTabledt,HttpRequestBaseRequest)       {           stringstrModelFile=””;           strModelFile=Request.PhysicalApplicationPath+”ProjectList.xls”;

发表回复

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

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