美文网首页ios基础知识
SSL详解(个人理解)

SSL详解(个人理解)

作者: xiaoliang1 | 来源:发表于2017-02-08 14:18 被阅读843次
    howsslwork_clip_image002.gif
    一次完整的https请求大概是这样的。
    1.客户端服务器发出https,请求。
    2.服务器发送自己信息到客户端,包括服务器端公钥(.car证书文件) 等信息。
    3.客户端根据服务器发回来的 公钥 去自己钥匙串里面匹配本地证书(公钥),来判断证书是否过期,可用等。如果本地证书没有的话。就会弹出警告改证书不被信任,询问用户是否要安装这个证书。一旦安装,下次访问的时候再去自己的钥匙串里面去找的时候就能找到了。
    4.客户单服务器的证书加密随机值发给服务器(这个随机值在TCP协议里面会自动帮我加。OSX内核部分,我们都无法接触到。这个值我们改不了)。
    5.服务器用自己的 私钥 解密发回来,客户端校验这个随机值是否正确。双方信任对方。

    以上就是一次https握手过程。完成握手以后,就用公钥加密传输内容了。
    举个例子:

    1EA0B000-2937-4201-ABEE-D97CBE362D6A.jpg

    查看百度的https证书。苹果一般会自动更新自己 钥匙串 里面的权威机构的证书。

    QQ20170208-114019@2x.png

    以上是苹果钥匙串里已经安装的证书。

    QQ20170208-114134@2x.png QQ20170208-114222@2x.png

    以上是百度的买的证书服务商。查了一下是比利时的。

    这里说一下,我们开发中用到https。(ios9开始默认开始https)
    一般只要你买的证书大部分都是直接过。客户端什么都不用做,只要把http改https就行了。你买的权威机构证书,手机端默认在钥匙串里面安装了默认信任机构的证书。(特别权威的https在访问的网址那里会有绿色符号)。所以网上说了一堆什么什么的,都不用管只要你用权威机构的,客户端什么都不用做。服务器端我就不知道了。阿里云貌似的就不用。客户端直接改https就行了。

    另外,费事的就是自制的证书了。苹果钥匙串里没有你的证书,不信任你。这时候可能要做一些功夫了。

    NSURLConnection的代理方法里面默认的https大概代码是这样的:

    // Now start the connection
    NSURL * httpsURL = [NSURL URLWithString:@"https://www.baidu.com"];
    self.connection = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:httpsURL] delegate:self];
         
    //回调
    - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
        //1)获取trust object
        SecTrustRef trust = challenge.protectionSpace.serverTrust;
        SecTrustResultType result;
         
        //2)SecTrustEvaluate对trust进行验证
        OSStatus status = SecTrustEvaluate(trust, &result);
        if (status == errSecSuccess &&
            (result == kSecTrustResultProceed ||
            result == kSecTrustResultUnspecified)) {
             
            //3)验证成功,生成NSURLCredential凭证cred,告知challenge的sender使用这个凭证来继续连接
            NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
            [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
             
        } else {
         
            //5)验证失败,取消这次验证流程
            [challenge.sender cancelAuthenticationChallenge:challenge];
             
      }
    }
    

    在一般购买的证书。这个代理根本不用实现。啥都不用做。

    自制的证书代码是这样的:

    //先导入证书
    NSString * cerPath = ...; //证书的路径
    NSData * cerData = [NSData dataWithContentsOfFile:cerPath];
    SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(cerData));
    self.trustedCertificates = @[CFBridgingRelease(certificate)];
    //回调
    - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
        //1)获取trust object
        SecTrustRef trust = challenge.protectionSpace.serverTrust;
        SecTrustResultType result;
        //注意:这里将之前导入的证书设置成下面验证的Trust Object的anchor certificate
        SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)self.trustedCertificates);
        //2)SecTrustEvaluate会查找前面SecTrustSetAnchorCertificates设置的证书或者系统默认提供的证书,对trust进行验证
        OSStatus status = SecTrustEvaluate(trust, &result);
        if (status == errSecSuccess &&
            (result == kSecTrustResultProceed ||
            result == kSecTrustResultUnspecified)) {
             
            //3)验证成功,生成NSURLCredential凭证cred,告知challenge的sender使用这个凭证来继续连接
            NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
            [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
             
        } else {
         
            //5)验证失败,取消这次验证流程
            [challenge.sender cancelAuthenticationChallenge:challenge];
             
      }
    }
    

    在老版本的ios系统里 可能 不实现这个方法没问题。在新版本的ios系统里,恐怕不行。

    为了做一次实验。用百度写了一个小demo.

    QQ20170208-114134@2x.png QQ20170208-122708@2x.png QQ20170208-122726@2x.png

    找到刚刚百度用的证书,把他导出来然后添加项目工程了。用的时候,别用代理里面返回的证书信息。别别去钥匙串里面查找了,直接用我导的这个证书。

    - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
    {
        NSString * cerPath = [[NSBundle mainBundle] pathForResource:@"11111" ofType:@"cer"]; //证书的路径
        NSData * cerData = [NSData dataWithContentsOfFile:cerPath];
        SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(cerData));
        //    self.trustedCertificates = @[CFBridgingRelease(certificate)];
        
        SecTrustRef trust = challenge.protectionSpace.serverTrust;
        SecTrustResultType result;
        //注意:这里将之前导入的证书设置成下面验证的Trust Object的anchor certificate
        SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)@[CFBridgingRelease(certificate)]);
        //2)SecTrustEvaluate会查找前面SecTrustSetAnchorCertificates设置的证书或者系统默认提供的证书,对trust进行验证
        NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
        [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
        
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    {
        NSLog(@"%@",response);
        
    }
    
    

    最后我们发现我们也能收到response.

    QQ20170208-123327@2x.png

    所以。本地证书和服务器证书是可以互相校验的。放哪无所谓。只不过默认去钥匙串里面找。

    QQ20170208-123619@2x.png
    Charles这个工具用过的都知道。这里直接叫青花瓷吧。
    他是怎么工作的呢。
    他就像客户端服务器之间的一个中间人。我们叫他代理服务器吧。
    文章的开始就说了https请求的过程。
    青花瓷在第二步开始的时候就把青花瓷自己的 公钥 返回给客户端了。
    客户端请求信息作为自己的信息 请求去访问服务器
    重新屡一下:

    1.客户端发送请求到青花瓷
    2青花瓷发送客户端请求到服务器
    3.服务器返回 公钥信息到青花瓷
    4.青花瓷把自己的 公钥 发送给客户端
    5.客户端认证青花瓷的证书。
    6.客户端青花瓷公钥 加密随机值发给青花瓷
    7.青花瓷服务器公钥加密随机值发给 服务器
    8.服务器用自己的私钥解密随机值,然后发给青花瓷
    9.青花瓷用自己的私钥加密随机值,然后发送给客户端
    10.客户端对比。完成握手。
    11.青花瓷对比。完整握手。
    以后。客户端就用青花瓷公钥加密数据发给青花瓷青花瓷用自己私钥解密,展现给我们看。然后用服务器公钥加密已经解密的数据发给服务器
    就这样,帮我们拦截所有请求。

    这也是为什么青花瓷拦截https时客户端要安装一份青花瓷的公钥证书,这样在第5步时候,客户端钥匙串找证书的时候正好能找到。

    目前大部分app的https都能抓到数据。
    但是某些apps 用自己的一套加密加密,然后用https加密传传输。所以有时候,我们在青花瓷看到也是加密数据。

    有图有证据:

    - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
    {
        //1)获取trust object
        SecTrustRef trust = challenge.protectionSpace.serverTrust;
        SecTrustResultType result;
        
        SecKeyRef  xxx =SecTrustCopyPublicKey(trust);
        
        SecCertificateRef  pppp = SecTrustGetCertificateAtIndex(trust,0);
        
        //2)SecTrustEvaluate对trust进行验证
    }
    

    未用青花瓷时:证书信息

    QQ20170208-130351@2x.png

    青花瓷时:证书信息

    QQ20170208-130513@2x.png

    两个证书明显不一样了。

    木有木发现appstore有部分请求,用青花瓷拦截不到。
    因为在第5步的时候,苹果没有根据服务器返回的证书来加密数据。而是直接用自己已知公钥证书加密返回,这样即使你钥匙串里面安装的别人的证书的时候也没有用了。

    代码类似上面“用百度写了一个小demo”那里的代码:

    - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
    {
        NSString * cerPath = [[NSBundle mainBundle] pathForResource:@"11111" ofType:@"cer"]; //证书的路径
        NSData * cerData = [NSData dataWithContentsOfFile:cerPath];
        SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(cerData));
        //    self.trustedCertificates = @[CFBridgingRelease(certificate)];
        
        SecTrustRef trust = challenge.protectionSpace.serverTrust;
        SecTrustResultType result;
        //注意:这里将之前导入的证书设置成下面验证的Trust Object的anchor certificate
        SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)@[CFBridgingRelease(certificate)]);
        //2)SecTrustEvaluate会查找前面SecTrustSetAnchorCertificates设置的证书或者系统默认提供的证书,对trust进行验证
        NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
        [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
     
    }
    

    不去判断公钥证书是否安装、是否过期,也不去查找。直接用我知道的公钥证书去加密。这样就可以防止青花瓷做中间人拦截数据。(不查找,直接用已知的公钥证书和发过来的公钥证书对比信息,用服务器发过来的公钥信息查找证书直接判断过期、可用。还是有风险的)
    这是青花瓷拦截不到了

    QQ20170208-132115@2x.png

    猜测苹果可能在这里做了判断。

    保险的做法用了https之外,吧数据用自己的一套加密机制在加密一遍。

    几个测试例子:
    https://pan.baidu.com/s/1i5cB6Yh
    用到某个测试就有个注释去掉就行了

    参考文章:
    http://www.cocoachina.com/ios/20150811/12947.html

    相关文章

      网友评论

      • xiaoliang1:理解的不够太深入。不过你理解这些在做ios https适配的时候不会再有什么迟疑了。看到网上好多说的不够好,还有有些事错的,就是想帮你彻底理解而已。
      • xiaoliang1:有理解不对的地方,请指出,我好及时更正

      本文标题:SSL详解(个人理解)

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