iOS HTTPS 双向认证

作者: MrSong | 来源:发表于2017-04-18 17:58 被阅读541次

iOS HTTPS 双向认证

@(iOS)[网络,HTTPS]

搞了半天,记录一下,坑很多。
双向认证,就是在访问网络的时候进行证书认证,首先本地需要一个服务器证书,一个客户端证书。客户端发送请求,服务器返回服务器证书和本地服务器证书比对,然后客户端发送客户端证书到服务器。如果全部匹配就返回加密算法,然后可以访问网络,否则就不能访问。

流程

  • 1.需要服务端提供认证证书.crt文件,然后自己导出成.cer文件
  • 2.将导出的cer证书加入到项目中,注意勾选相应的target不然可能获取证书路径为nil
  • 3.通过cer证书生成证书校验的安全策略
  • 4.在AFNetworking的网络请求中设置安全策略:[_manager setSecurityPolicy:[CertificatehttpsTools customSecurityPolicy]];
  • 5.通过抓包工具Charles检验请求和返回的内容是否加密

证书

  • 需要server.cer 和client.p12两个文件,用的自签名证书,所以要配置项目info.plist,增加下面几个属性
  • 注意域名和服务器配置有关
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>xxxx.com</key>
            <dict>
                <key>NSExceptionAllowsInsecureHTTPLoads</key>
                <true/>
                <key>NSExceptionMinimumTLSVersion</key>
                <string>TLSv1.0</string>
                <key>NSExceptionRequiresForwardSecrecy</key>
                <false/>
                <key>NSIncludesSubdomains</key>
                <true/>
            </dict>
        </dict>
    </dict>

网络

  • AFN3.0
  • 然后就是设置AFN的安全参数 AFSecurityPolicy
  • 在初始化网络工具类是指定这个参数
  • 需要注意这个baseUrl问题,指定类似这种就行 https://192.168.0.22" ,不然就会报错 'Invalid Security Policy', reason: 'A security policy configured with AFSSLPinningModeCertificate can only be applied on a manager with a secure base URL (i.e. https)'
- (void)setupAFNetwork{
    AFHTTPSessionManager *manager = [[AFHTTPSessionManager manager] initWithBaseURL:[NSURL URLWithString:BaseURL]];
    manager.securityPolicy = [self getCustomHttpsPolicy:manager];
    manager.securityPolicy.allowInvalidCertificates = YES;
    manager.responseSerializer.acceptableContentTypes = [manager.responseSerializer.acceptableContentTypes setByAddingObject:@"text/html"];
    
    self.httpSessionManager = manager;
    
}
// 配置安全参数
-(AFSecurityPolicy*) getCustomHttpsPolicy:(AFHTTPSessionManager*)manager{
    
    //https 公钥证书配置
    
    NSString *certFilePath = [[NSBundle mainBundle] pathForResource:@"serverapple" ofType:@"cer"];
    
    NSData *certData = [NSData dataWithContentsOfFile:certFilePath];
    
    NSSet *certSet = [NSSet setWithObject:certData];
    
    AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:certSet];
    
    policy.allowInvalidCertificates = YES;
    
    policy.validatesDomainName = NO;//是否校验证书上域名与请求域名一致
   
    //https回调 客户端验证
    
    [manager setSessionDidBecomeInvalidBlock:^(NSURLSession * _Nonnull session, NSError * _Nonnull error) {
        
        NSLog(@"setSessionDidBecomeInvalidBlock");
        
    }];
    
    __weak typeof(manager)weakManger = manager;
    
    __weak typeof(self)weakSelf = self;
    
    //客户端请求验证 重写 setSessionDidReceiveAuthenticationChallengeBlock 方法
    
    [manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession*session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing*_credential) {
        
        NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        
        __autoreleasing NSURLCredential *credential =nil;
        
        if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            
            if([weakManger.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
                
                credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
                
                if(credential) {
                    
                    disposition =NSURLSessionAuthChallengeUseCredential;
                    
                } else {
                    
                    disposition =NSURLSessionAuthChallengePerformDefaultHandling;
                    
                }
                
            } else {
                
                disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
                
            }
            
        } else {
            
            // client authentication
            
            SecIdentityRef identity = NULL;
            
            SecTrustRef trust = NULL;
            
            NSString *p12 = [[NSBundle mainBundle] pathForResource:@"clientapple"ofType:@"p12"];
            
            NSFileManager *fileManager =[NSFileManager defaultManager];
            
            if(![fileManager fileExistsAtPath:p12])
                
            {
                
                NSLog(@"client.p12:not exist");
                
            }
            
            else
                
            {
                
                NSData *PKCS12Data = [NSData dataWithContentsOfFile:p12];
                
                if ([[weakSelf class]extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data])
                    
                {
                    
                    SecCertificateRef certificate = NULL;
                    
                    SecIdentityCopyCertificate(identity, &certificate);
                    
                    const void*certs[] = {certificate};
                    
                    CFArrayRef certArray =CFArrayCreate(kCFAllocatorDefault, certs,1,NULL);
                    
                    credential =[NSURLCredential credentialWithIdentity:identity certificates:(__bridge  NSArray*)certArray persistence:NSURLCredentialPersistencePermanent];
                    
                    disposition =NSURLSessionAuthChallengeUseCredential;
                    
                }
                
            }
            
        }
        
        *_credential = credential;
        
        return disposition;
        
    }];
    
    return policy;
    
}


+ (BOOL)extractIdentity:(SecIdentityRef*)outIdentity andTrust:(SecTrustRef *)outTrust fromPKCS12Data:(NSData *)inPKCS12Data {
    
    OSStatus securityError = errSecSuccess;
    
    //client certificate password
    
    NSDictionary*optionsDictionary = [NSDictionary dictionaryWithObject:@"123456"
                                      
                                                                 forKey:(__bridge id)kSecImportExportPassphrase];
    
    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    
    securityError = SecPKCS12Import((__bridge CFDataRef)inPKCS12Data,(__bridge CFDictionaryRef)optionsDictionary,&items);
    
    if(securityError == 0) {
        
        CFDictionaryRef myIdentityAndTrust =CFArrayGetValueAtIndex(items,0);
        
        const void*tempIdentity =NULL;
        
        tempIdentity= CFDictionaryGetValue (myIdentityAndTrust,kSecImportItemIdentity);
        
        *outIdentity = (SecIdentityRef)tempIdentity;
        
        const void*tempTrust =NULL;
        
        tempTrust = CFDictionaryGetValue(myIdentityAndTrust,kSecImportItemTrust);
        
        *outTrust = (SecTrustRef)tempTrust;
        
    } else {
        
        NSLog(@"Failedwith error code %d",(int)securityError);
        
        return NO;
        
    }
    
    return YES;
    
}

参考文章
参考文章

相关文章

  • iOS HTTPS 双向认证

    iOS HTTPS 双向认证 @(iOS)[网络,HTTPS] 搞了半天,记录一下,坑很多。双向认证,就是在访问网...

  • iOS https 双向认证

    /** 一.非浏览器应用(iOS app)与服务器AFNetworking HTTPS ssl认证 虽然是HTTP...

  • iOS HTTPS双向认证

    一般情况下对于HTTPS,如果公司申请认证之后,客户端是不需要做什么操作。但是如果是自建证书,没有通过CA认证的话...

  • iOS中的安全与加密

    iOS中的安全与加密 一。HTTPS双向认证 Charles是大家所熟悉的抓包工具,如果网络请求未经过双向认证,那...

  • iOS中的HTTPS认证

    一、HTTPS认证 1. 会话认证机制 iOS 中会话认证机制共有四种,大体分为两种类型: 单向认证双向认证; N...

  • https双向认证

    一、运行环境 win7_64studio3.1.3IDEA2017.3JDK1.8Sprint Boot 2.0....

  • HTTPS双向认证

    双向认证,顾名思义,客户端和服务器端都需要验证对方的身份,在建立HTTPS连接的过程中,握手的流程比单向认证多了几...

  • Https双向认证-合集

    iOS实用篇:Https双向认证[https://www.jianshu.com/p/72bf60b5f94d]i...

  • iOS实用篇:Https双向认证

    年前的时候,关于苹果要强制https的传言四起,虽然结果只是一个“谣言”,但是很明显的这是迟早会到来的,间接上加速...

  • https双向认证 CA认证

    CA证书认证:http://blog.csdn.net/langeldep/article/details/548...

网友评论

  • 大于于:client.p12怎么生成?
    MrSong:@Android_小宝 你可以网上找一下。几个命令就行了

本文标题:iOS HTTPS 双向认证

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