请求https The certificate for this server is invalid -1202

请求https The certificate for this server is invalid -1202_第1张图片
先开心一下

情况说明:用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

        只要填上这些就直接能用

请求https The certificate for this server is invalid -1202_第2张图片
请求https The certificate for this server is invalid -1202_第3张图片

第二种:生成.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还是报错

请求https The certificate for this server is invalid -1202_第4张图片

相关知识点:

简单的来说,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 server is invalid -1202)