美文网首页
峰回路转之HTTPS

峰回路转之HTTPS

作者: lmfei | 来源:发表于2020-03-06 20:14 被阅读0次

    自iOS 9以后,苹果发出强制使用HTTPS协议的规定,虽然到现在也还没有强制实行,不过大多数用户早已使用HTTPS协议替换原有的HTTP协议。相对HTTP,HTTPS更安全,它是在tcp/ip层加入了SSL/TSL加密层。HTTPS的作用是防止中间人攻击的,下面我们来看下有关HTTPS的一些tip

    首先我们先来了解下在HTTPS下客户端与服务端之间的一个交互流程:

    1. 客户端发送SSL版本信息、random-c、加密算法至服务端
    2. 服务端发送SSL版本、随机数random-s等信息及服务器公钥至客户端- 非对称加密,耗时,性能低
    3. 客户端校验证书是否合法,合法继续,否则警告
    4. 服务端选择加密程度高的加密方式
    5. 将选择好的加密方式明文发送给客户端
    6. 客户端收到加密方式后,产生随机码(Pre-master),作为加密对称密钥,使用公钥加密后,发给服务端
    7. 服务端使用私钥解密,获得对称加密的密钥
    8. 使用随机码对称加密,进行通讯

    上述交互流程中,与客户端密切相关的就是证书校验部分,下面我们来具体看下这个部分的代码实现

    首先看下几个重要的类及属性
    • SecTrustRef - 需要验证的信任对象,包含待验证的证书和支持的验证方法等
    • SecTrustResultType - 验证结果,kSecTrustResultProceed表示server trust验证成功,且该验证得到了用户认可,用户点击了always trust;kSecTrustResultUnspecified表示server trust验证成功,此证书被暗中信任,但用户并没有显式的决定信任该证书
    • SecTrustEvaluate-证书校验函数,在函数的内部递归的从叶节点到根证书验证。需要验证证书本身的合法性(验证签名完整性,验证证书有效期等);验证证书颁发者的合法性。
    • NSURLAuthenticationChallenge
      protectionSpace:NSURLProtectionSpace - 保存服务器中希望的认证方式以及协议,主机端口号等信息
      这个类中的属性
      host - 主机地址
      port - 端口号
      authenticationMethod - 指定授权方式,例如NSURLAuthenticationMethodServerTrust为ServerTrust认证、
    • proposedCredential:NSURLCredential - 建议使用的证书

    有了上面的了解,我们就更容易看明白下面代码实现

    自签名证书单向校验

    针对NSURLConnection的适配
    - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
    
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]){
        
            [[challenge sender]  useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
            
            [[challenge sender]  continueWithoutCredentialForAuthenticationChallenge: challenge];
        }
    }
    
    针对NSURLSession适配
    - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
    {
        NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        __block NSURLCredential *credential = nil;
        // 判断返回的证书是否是服务器所信任的
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
        {
            credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            if (credential)
            {
                //使用返回的证书
                disposition = NSURLSessionAuthChallengeUseCredential; 
            }
            else
            {
                //忽略证书
                disposition = NSURLSessionAuthChallengePerformDefaultHandling; 
            }
        }
        else
        {
            //取消请求
            disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; 
        }
        //安装证书
        if (completionHandler)   {
            completionHandler(disposition, credential);
        }
    }
    

    证书预置本地的单向校验

    针对URLSession进行说明

    - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
    {
          SecTrustRef trustRef = challenge.protectionSpace.serverTrust;
          SecCertificateRef certificateRef = SecTrustGetCertificateAtIndex(servertrust, 0);
          NSData *certidata = CFBridgingRelease(CFBridgingRetain(CFBridgingRelease(SecCertificateCopyData(certificateRef))));
          NSString *path = [[NSBundle mainBundle] pathForResource:@"证书名称" ofType:@"cer"];
      //    NSLog(@"证书 : %@",path);
          NSData *localCertiData = [NSData dataWithContentsOfFile:path];
          if ([certidata isEqualToData:localCertiData]) {
              NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:servertrust];
              [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
              completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
      //        NSLog(@"服务端证书认证通过");
          }else {
              completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
              NSLog(@"服务端认证失败");
          }
    
    }
    

    至此,HTTPS的记录就到此结束了。

    生活如此美好,今天就点到为止。。。

    相关文章

      网友评论

          本文标题:峰回路转之HTTPS

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