iOS 中HTTPS 的使用

作者: Dimon_Hu | 来源:发表于2016-12-14 14:22 被阅读629次

    谣言四起,大限将至。各种谣言皆因苹果开发者大会开始,从那个时间开始,都说2017年1月1日为HPPTS即将开始的日子。从此大航海时代就要开始了。从此就成了我挥之不去的心魔,吓得本大少和服务器端调呀调。总算调好了。好吧,我们聊聊HTTPS。

    一、HTTPS

    HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。 它是一个URI scheme(抽象标识符体系),句法类同http:体系。用于安全的HTTP数据传输。https:URL表明它使用了HTTP,但HTTPS存在不同于HTTP的默认端口及一个加密/身份验证层(在HTTP与TCP之间)。这个系统的最初研发由网景公司(Netscape)进行,并内置于其浏览器Netscape Navigator中,提供了身份验证与加密通讯方法。(摘自百度百科)

    PKI(公钥基础设施)技术是HTTPS的基础,PKI与非对称密钥加密技术密切相关,包括消息摘要、数字签名和加密服务,而数字证书以及证书机构(CA – Certificate Authority)是PKI中的重要概念。

    二、Apple CSR CER P12 mobileprovition 到底是什么

    • CSR(Certificate Signing Request)钥匙串文件 为生成证书做基础,要生成CER证书必须要有CSR私钥,此私钥包含了用户自己的一些信息。这个文件是保存在我们的mac的(keychain)里面的, 此文件包含了(公钥和私钥)

    • CER 包含了开发者信息和公钥

    • P12 它不仅包含CER的信息,还有私钥信息,即: P12备份文件 = CER文件 + 私钥;所以有了这个p12就再也不用担心证书丢失了

    • mobileprovition 包含了上述所有内容 Certificate && App ID && Device, 这个Provisioning Profile文件会在打包时嵌入到.ipa的包里。本人理解的是 可以真机调试的凭证。

    三、App Transport Security

    iOS9中新增App Transport Security(简称ATS)特性, 主要使到原来请求的时候用到的HTTP,都转向TLS1.2协议进行传输。这也意味着所有的HTTP协议都强制使用了HTTPS协议进行传输。
    一般我们如果还是使用的http,不更新的话,可通过在 Info.plist 中声明,倒退回不安全的网络请求


    111.png

    然后好像我说这么多是不是一点屌用都没用?想知道这么改不?接下来我们继续说正事了。我这里简单说下双向认证的自签名HTTPS证书的使用。放心,不坑。

    准备证书

    首先找后台要一个证书(SSL证书,一般你跟后台说要弄https,然后让他给你个证书,他就知道了),
    我们需要的是.cer的证书。但是后台可能给我们的是.crt的证书。
    我们需要转换一下:打开终端 -> cd到.crt证书路径 -> 输入openssl x509 -in 你的证书.crt -out 你的证书.cer -outform der
    证书就准备好了,拖入工程,记得选copy。一般叫做servicer.cer
    --此段引用自大神vision_colion的文章,他文章里面有单向认证的哦。
    然后我们还得需要一个client.p12证书.还是问服务器端给。

    屏幕快照 2016-12-15 下午2.45.30.png
    屏幕快照 2016-12-15 下午2.47.06.png
    //AFNetWoking3.0以上适用
    - (void)testAFNetWorking{
    
     NSString *certFilePath = [[NSBundle mainBundle] pathForResource:@"server" 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;
    
     _manager = [AFHTTPSessionManager manager];
     _manager.securityPolicy = policy;
     _manager.requestSerializer = [AFHTTPRequestSerializer serializer];
     _manager.responseSerializer = [AFHTTPResponseSerializer serializer];
     _manager.responseSerializer.acceptableContentTypes =  [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html", nil];
     //    [manager.securityPolicy setAllowInvalidCertificates:YES];
     //关闭缓存避免干扰测试r
     _manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
     [_manager setSessionDidBecomeInvalidBlock:^(NSURLSession * _Nonnull session, NSError * _Nonnull error) {
     NSLog(@"setSessionDidBecomeInvalidBlock");
     }];
     __weak typeof(self)weakSelf = self;
     [_manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession*session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing*_credential) {
     NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
     __autoreleasing NSURLCredential *credential;
     if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
     if([weakSelf.manager.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:@"client"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;
     }];
    
    [_manager POST:@"https://192.168.0.51/dw-api-V2.0/user/login.p" parameters:@{@"yhzh":@"18639398700",@"infoMap":@"g+bc4UTf3wHjabyKW+RYqcervD+/HSJXFIRKdVCQYldN5j85x//6eVUUZsidGrUpE+MJCvHdo7/E4EjNT+hjvnYa5qJ9ep0maOWfvq6AkIinjjc9cQJ0cfEAsg2LnV17hJKi3hCRrjbQJfAqUB2C3IetHK9Gg0voOmcTK2IA1J/V+KRcCtb1XncXDxVnXiUT/qBIQKPEg3/dt5ISLHpdXQ=="} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSString *message = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
        NSLog(@"%@",message);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"%@",error);
    }];
    }
    
    //验证你P12证书的
    + (BOOL)extractIdentity:(SecIdentityRef*)outIdentity andTrust:(SecTrustRef *)outTrust fromPKCS12Data:(NSData *)inPKCS12Data {
        OSStatus securityError = errSecSuccess;
        //client certificate password 你的p12密码
        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;
    }
    

    参考文档

    苹果官方文档
    lanp74的博客

    相关文章

      网友评论

      • _Waiting_:大神,我可以膜拜你嘛
        Dimon_Hu:@_Waiting_ 收下你的膝盖:smile::smile:
      • Sunshine_Boys:赶紧写一个 swift 版本的:grin:
      • nzkaw:小哥,6
        Dimon_Hu:@云清淡 哈哈,还需要补充。等元旦晚上没事我把需要的补全
      • 透支未来:胡哥 吊得很啊 牛逼 6666
        Dimon_Hu:@透支未来 一般般啦
      • 大兵布莱恩特:老弟写的不赖 哥哥正在看着学习
        Dimon_Hu:@大兵布莱恩特 咳咳,和你比还差的很远呀。:joy::joy:
      • vision_colion:楼主,准备证书那一段文字好熟悉啊:smirk:
        Dimon_Hu:@vision_colion 咳咳,得赶紧打上你的大名。
        vision_colion:@Dimon_Hu 卧槽,因为那段文字就是我写的:sweat:
        Dimon_Hu:@vision_colion 小伙子,好眼力
      • years_han:写的真好啊 :smile: :smile:
        Dimon_Hu:@years_han 后期再补充点可信任证书的东西
      • CoreCoder:上线啦吗?我的神:heart_eyes::heart_eyes::heart_eyes:
        Dimon_Hu:@WYJdesigner 项目中使用了.以上线
      • ios哥哥:我擦,这个666.。。。这个是我男神
        Dimon_Hu:@ios哥哥 小伙,跟哥哥好好混

      本文标题:iOS 中HTTPS 的使用

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