iOS内置证书,校验https请求

Posted Shuffle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS内置证书,校验https请求相关的知识,希望对你有一定的参考价值。

有些情况处于安全的考虑需要https请求,但是为了防止域名解析很多情况下会使用IP进行访问。一般的服务不会针对IP去申请证书,所以我们可以自己实现ssl登录过程,保证请求的安全性。

一.首先需要自己本地生成ssl证书以及搭建一个本地服务

Mac apache本地配置ssl证书 及 ios OTA部署: http://www.jianshu.com/p/bd016015efe7

生成的crt转换成cer的方法

openssl x509 -in test.crt -out test.cer -outform der

二.实现代码

初始化NSURLSession,将证书导入对应的xcode项目中

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
configuration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
configuration.timeoutIntervalForRequest = 120;
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
                                                 delegate:self
                                            delegateQueue:[[NSOperationQueue alloc] init]];

生成的ssl证书需要设置ip,而且校验的时候也会去校验这个ip。但是更多情况下是不去校验这个ip的,因为代码内部可能只有一个证书,但是服务可能会有多套部署,如果去校验ip,会限制服务的扩展(很多项目都会做自己的DNS策略,ip经常会改变)。

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler
{
    NSString *host = challenge.protectionSpace.host;
    BOOL isIp = [self _isIp:host];
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        if (isIp) {
            // Get
            NSData *certData =[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"server" ofType:@"cer"]];
            if (certData) {
                SecTrustRef trust = [[challenge protectionSpace] serverTrust];
                
                NSMutableArray *policies = [NSMutableArray array];
          //如果需要校验IP,需要把下面的注释打开,把下面X509这段代码注释掉
          //[policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)]; [policies addObject:(__bridge_transfer
id)SecPolicyCreateBasicX509()]; SecTrustSetPolicies(trust, (__bridge CFArrayRef)policies); SecCertificateRef rootcert = SecCertificateCreateWithData(kCFAllocatorDefault,CFBridgingRetain(certData)); const void *array[1] = { rootcert }; CFArrayRef certs = CFArrayCreate(NULL, array, 1, &kCFTypeArrayCallBacks); int err; SecTrustResultType trustResult = 0; err = SecTrustSetAnchorCertificates(trust, certs); if (err == noErr) { err = SecTrustEvaluate(trust,&trustResult); } BOOL trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified)); if (!trusted) { NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] ; completionHandler(NSURLSessionAuthChallengeUseCredential, credential); } else { //如果校验失败了,就校验一下证书数据,一般不建议走这段逻辑,因为不能够保证服务是否安全 NSMutableArray *pinnedCertificates = [NSMutableArray array]; [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData)]; SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)pinnedCertificates); NSArray *serverCertificates = [self _certificateTrustChainForServerTrust:trust]; for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) { if ([certData isEqualToData:trustChainCertificate]) { NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] ; completionHandler(NSURLSessionAuthChallengeUseCredential, credential); } } } } } else { NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; completionHandler(NSURLSessionAuthChallengeUseCredential, credential); } } } - (BOOL)_isIp:(NSString*)aHost { NSString *regex = @"((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)"; NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; return [pred evaluateWithObject:aHost]; } - (NSArray *)_certificateTrustChainForServerTrust:(SecTrustRef)serverTrust { CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust); NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount]; for (CFIndex i = 0; i < certificateCount; i++) { SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i); [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)]; } return [NSArray arrayWithArray:trustChain]; }

https请求构建

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://127.0.0.1:443/index.html"]];
    
    NSURLSessionDataTask *task = [_session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        completionHandler(((NSHTTPURLResponse*)response).statusCode, data ? [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] : nil, error);
    }];
    
    [task resume];

网上的例子有很多,但是很多没有考虑不校验IP的场景。希望本文能够给大家一个参考



以上是关于iOS内置证书,校验https请求的主要内容,如果未能解决你的问题,请参考以下文章

Android App 安全的HTTPS 通信

Https 证书校验加密机制

解决「 HTTPDNS + HTTPS 」的证书校验问题

乐鑫Esp32学习之旅30 对接华为IoT物联网平台适配踩坑,使用ESP-IDF 编程使用HTTPS请求固件跳过证书校验,实现OTA远程升级文件。(附带源码)

android中使用https是否对服务证书合法性校验的新的体会

c# https请求忽略证书验证_各种编程语言忽略http的SSL证书认证