iOS开发(OC)

iOS - HTTPS自制证书验证

2017-12-08  本文已影响197人  yanhooIT

证书类型

自己实现自制证书验证

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
    // 证书的处理方式
    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
    // 被处理的证书
    NSURLCredential *credential = nil;

    do
    {
        // 1、校验认证方式是否为NSURLAuthenticationMethodServerTrust
        if (![challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
            break; /* failed */

        // 2、获取服务端返回的证书
        SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;

        // 3、从app的资源文件中获取内置的本地证书(可以是多个,这里只演示只有一个内置证书)
        // custom是你证书的名称,记得替换
        NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"custom" ofType:@"cer"];
        NSData *caCert = [NSData dataWithContentsOfFile:cerPath];
        if(nil != caCert) {
            // 创建证书
            SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert);
//            NSCAssert(caRef != nil, @"caRef is nil");
            if(nil == caRef)
                break; /* failed */

            // 添加自制证书,这里表明了可以添加多张自制证书
            NSArray *caArray = @[(__bridge id)(caRef)];
//            NSCAssert(caArray != nil, @"caArray is nil");
            if(nil == caArray)
                break; /* failed */

            // 将内置的本地证书列表设置为服务端证书的根证书
            // 设置可信任证书列表,设置后就只会在设置的证书列表中进行验证,屏蔽掉系统的证书列表
            OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);
            // 要使系统的证书列表继续起作用可以调用此方法,第二个参数设置成NO即可
            SecTrustSetAnchorCertificatesOnly(serverTrust, NO);
//            NSCAssert(errSecSuccess == status, @"SecTrustSetAnchorCertificates failed");
            if(errSecSuccess != status)// errSecSuccess表示没有错误
                break; /* failed */
        }

        // 4、使用本地导入的证书列表验证服务器的证书是否可信
        SecTrustResultType result = -1;
        OSStatus status = SecTrustEvaluate(serverTrust, &result);
        if(errSecSuccess != status)
            break; /* failed */
        // kSecTrustResultUnspecified and kSecTrustResultProceed are success
        BOOL allowConnect = (result == kSecTrustResultUnspecified)// 证书通过验证,是由于用户没有设置这些证书是否被信任
                            || (result == kSecTrustResultProceed);// 证书通过验证,用户有操作设置了证书被信任
        if (!allowConnect)
            break; /* failed */

        // 5、设置证书的处理方式
        credential = [NSURLCredential credentialForTrust:serverTrust];
        disposition = NSURLSessionAuthChallengeUseCredential;
    } while(0);

    // 6、告知系统如何处理自制证书
    if(completionHandler) completionHandler(disposition, credential);
}

通过AFN实现自制证书验证

// 记得设置个AFHTTPSessionManager属性
@property (nonatomic, strong) AFHTTPSessionManager *sessionManager;

- (void)validateCerByAFN {
    _sessionManager = [AFHTTPSessionManager manager];

    // 创建安全策略
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    // 是否允许使用自制证书
    securityPolicy.allowInvalidCertificates = YES;
    // 是否需要验证域名,默认YES
    securityPolicy.validatesDomainName = YES;
    _sessionManager.securityPolicy = securityPolicy;

    // 响应数据序列化格式
    _sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];
    // 设置超时
    _sessionManager.requestSerializer.timeoutInterval = 30.f;
    // 缓存策略
    _sessionManager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringCacheData;
    // 接受的返回数据类型
    _sessionManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", @"text/json", @"text/plain", @"text/javascript", @"text/xml", @"image/*", nil];
    // 打开状态栏的等待菊花
//    [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;

    __weak typeof(self) weakSelf = self;
    [_sessionManager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing *_credential)
    {
        // 1、校验认证方式是否为NSURLAuthenticationMethodServerTrust
        if (![challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            return NSURLSessionAuthChallengePerformDefaultHandling;
        }

        // 2、设置自制证书,可以导入多张自制证书(也就是个循环,这里就不演示了)
        // custom是你证书的名称,记得替换
        NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"custom" ofType:@"cer"];
        if(cerPath != nil) {
            NSData *caCert = [NSData dataWithContentsOfFile:cerPath];

            // 将内置的本地证书列表赋值给AFN,便于后期基于此证书列表进行验证
            NSSet *cerArray = [[NSSet alloc] initWithObjects:caCert, nil];
            weakSelf.sessionManager.securityPolicy.pinnedCertificates = cerArray;

            // 创建证书
            SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert);
            // 从这个数组可以看出是可以有多张本地自制证书
            NSArray *caArray = @[(__bridge id)(caRef)];
            // 获取服务端返回的证书
            SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
            // 将内置的本地证书列表设置为服务端证书的根证书
            // 设置可信任证书列表,设置后就只会在设置的证书列表中进行验证,屏蔽掉系统的证书列表
            OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);
            if(status == errSecSuccess) {// 表名设置成功
                // 要使系统的证书列表继续起作用可以调用此方法,第二个参数设置成NO即可
                SecTrustSetAnchorCertificatesOnly(serverTrust, NO);
            }
        }

        // 证书验证,获取证书的处理方式
        NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        if ([weakSelf.sessionManager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
            disposition = NSURLSessionAuthChallengeUseCredential;
        } else {
            disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
        }

        return disposition;
    }];
}

参考文章

上一篇 下一篇

猜你喜欢

热点阅读