美文网首页xyj
请求https The certificate for this

请求https The certificate for this

作者: so_bright | 来源:发表于2018-03-20 21:22 被阅读0次
    先开心一下

    情况说明:用post方法加载一个h5页面,请求的url为https的,web服务器挂的证书是自建证书,报错:

    2018-03-17 11:50:09.341674+0800 ICBCPayDemo[2216:1514635] TIC SSL Trust Error [7:0x1c01729c0]: 3:0

    2018-03-17 11:50:09.542477+0800 ICBCPayDemo[2216:1514635] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)

    2018-03-17 11:50:09.543400+0800 ICBCPayDemo[2216:1514635] Task .<0> HTTP load failed (error code: -1202 [3:-9813])

    2018-03-17 11:50:09.545843+0800 ICBCPayDemo[2216:1514343] NSURLConnection finished with error - code -1202

    2018-03-17 11:50:09.554470+0800 ICBCPayDemo[2216:1514273] didFailLoadWithError:Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “ebankp-pay-agn.sdc.cs.icbc” which could put your confidential information at risk." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9813, NSErrorPeerCertificateChainKey=

    几种解决方式:

    第一种:使用私有API,扩展NSURLRequest

            只要填上这些就直接能用

    第二种:生成.cer格式的证书,添加到工程中(未亲测)

            方法来源:http://www.jb51.net/article/132096.html

            1. 双击证书,这时证书已经添加到了钥匙串中

            2. 将cer 文件拖入工程中

            3. 如果使用的是AFNetwotking 的话,在代码中添加以下代码

    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

     //证书

     AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];

     manager.securityPolicy = securityPolicy;

    // 2.设置证书模式

     NSString * cerPath = [[NSBundle mainBundle] pathForResource:@"tomcat" ofType:@"cer"]; //tomcat是cer文件的名称

     NSData * cerData = [NSData dataWithContentsOfFile:cerPath];

     manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[[NSSet alloc] initWithObjects:cerData, nil]];

     // 客户端是否信任非法证书

     manager.securityPolicy.allowInvalidCertificates = YES;

     // 是否在证书域字段中验证域名

     [manager.securityPolicy setValidatesDomainName:NO];

            但这个cer文件不知道能不能导出来,没找到mac版chrome的导出方法,windows导出方式看:https://wdd.js.org/export-https-certificate-in-browser.html

            这个导出方式看起来靠谱点儿,但也没试,感觉应该由环境配置人员去搞:http://www.cocoachina.com/ios/20160928/17663.html

    第三:

    自建证书,将证书导入工程(其实没有自建证书怎么导入工程啊哈)

    - (void)viewDidLoad {

        [superviewDidLoad];

        //导入客户端证书

        NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"ca"ofType:@"cer"];

        NSData *data = [NSData dataWithContentsOfFile:cerPath];

        SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) data);

        self.trustedCerArr = @[(__bridge_transfer id)certificate];

        //发送请求

    NSURL *testURL = [NSURL URLWithString:@"https://casetree.cn/web/test/demo.php"];

        NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];

        NSURLSessionDataTask *task = [session dataTaskWithRequest:[NSURLRequest requestWithURL:testURL]];

        [task resume];

        // Do any additional setup after loading the view, typically from a nib.

    }

    #pragma mark - NSURLSessionDelegate

    - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge

     completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler{

        OSStatus err;

        NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;

        SecTrustResultType  trustResult = kSecTrustResultInvalid;

        NSURLCredential *credential = nil;

        //获取服务器的trust object

        SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;

        //将读取的证书设置为serverTrust的根证书

        err = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)self.trustedCerArr);

        if(err == noErr){

            //通过本地导入的证书来验证服务器的证书是否可信,如果将SecTrustSetAnchorCertificatesOnly设置为NO,则只要通过本地或者系统证书链任何一方认证就行

            err = SecTrustEvaluate(serverTrust, &trustResult);

        }

        if(err == errSecSuccess && (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified)){

            //认证成功,则创建一个凭证返回给服务器

            disposition = NSURLSessionAuthChallengeUseCredential;

            credential = [NSURLCredential credentialForTrust:serverTrust];

        }

        else{

            disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;

        }

        //回调凭证,传递给服务器

        if(completionHandler){

            completionHandler(disposition, credential);

        }

    }

    不能解决问题的方式:

    第一:

    写进plist还是报错

    相关知识点:

    简单的来说,SSL/TSL通过四次握手,主要交换三个信息:

    1. 数字证书:该证书包含了公钥等信息,一般是由服务器发给客户端,接收方通过验证这个证书是不是由信赖的CA签发,或者与本地的证书相对比,来判断证书是否可信;假如需要双向验证,则服务器和客户端都需要发送数字证书给对方验证;

    2. 三个随机数

    3. 加密通信协议


    验证证书的API

    相关的Api在Security Framework中,验证流程如下:

    1). 第一步,先获取需要验证的信任对象(Trust Object)。这个Trust Object在不同的应用场景下获取的方式都不一样,对于NSURLConnection来说,是从delegate方法-connection:willSendRequestForAuthenticationChallenge:回调回来的参数challenge中获取([challenge.protectionSpace serverTrust])。

    2). 使用系统默认验证方式验证Trust Object。SecTrustEvaluate会根据Trust Object的验证策略,一级一级往上,验证证书链上每一级数字签名的有效性(上一部分有讲解),从而评估证书的有效性。

    3). 如第二步验证通过了,一般的安全要求下,就可以直接验证通过,进入到下一步:使用Trust Object生成一份凭证([NSURLCredential credentialForTrust:serverTrust]),传入challenge的sender中([challenge.sender useCredential:cred forAuthenticationChallenge:challenge])处理,建立连接。

    4). 假如有更强的安全要求,可以继续对Trust Object进行更严格的验证。常用的方式是在本地导入证书,验证Trust Object与导入的证书是否匹配。更多的方法可以查看Enforcing Stricter Server Trust Evaluation,这一部分在讲解AFNetworking源码中会讲解到。

    5). 假如验证失败,取消此次Challenge-Response Authentication验证流程,拒绝连接请求。

    ps: 假如是自建证书的,则会跳过第二步,使用第三部进行验证,因为自建证书的根CA的数字签名未在操作系统的信任列表中。

    搭建完HTTPS服务器之后,可以使用nscurl命令来进行检测,查看建立的HTTPS服务器是否能通过ATS特性。

    1nscurl --ats-diagnostics --verbose https://casetree.cn

    那么,如何本地导入证书进行验证呢? 

    在这里先提一下,由于iOS客户端支持的证书是DER格式的,我们需要创建客户端证书。创建客户端证书,直接将服务端的CA根证书导出成DER格式就行。

    1openssl  x509  -inform PEM  -outform DER -inca.crt -out ca.cer

    另外也有说:把服务器给你的自签证的证书放入bundle一般是.cer文件

    相关文章

      网友评论

        本文标题:请求https The certificate for this

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