zoukankan      html  css  js  c++  java
  • ios Https问题

    HTTPS认证过程:
     
    ① 浏览器发送一个连接请求给安全服务器。
     
    ② 服务器将自己的证书,以及同证书相关的信息发送给客户浏览器。
     
    ③ 客户浏览器检查服务器送过来的证书是否是由自己信赖的 CA 中心所签发的。如果是,就继续执行协议;如果不是,客户浏览器就给客户一个警告消息:警告客户这个证书不是可以信赖的,询问客户是否需要继续。
     
    ④ 接着客户浏览器比较证书里的消息,例如域名和公钥,与服务器刚刚发送的相关消息是否一致,如果是一致的,客户浏览器认可这个服务器的合法身份。
     
    ⑤ 服务器要求客户发送客户自己的证书。收到后,服务器验证客户的证书,如果没有通过验证,拒绝连接;如果通过验证,服务器获得用户的公钥。
     
    ⑥ 客户浏览器告诉服务器自己所能够支持的通讯对称密码方案。
     
    ⑦ 服务器从客户发送过来的密码方案中,选择一种加密程度最高的密码方案,用客户的公钥加过密后通知浏览器。
     
    ⑧ 浏览器针对这个密码方案,选择一个通话密钥,接着用服务器的公钥加过密后发送给服务器。
     
    ⑨ 服务器接收到浏览器送过来的消息,用自己的私钥解密,获得通话密钥。
     
    ⑩ 服务器、浏览器接下来的通讯都是用对称密码方案,对称密钥是加过密的。
     
     
     
    https测试抓包
     
     
     
     
     
     
     
     
     
     
    https信任证书的三种方
     
    证书的信任是通过代理的方式进行信任(NSURLConnection和NSURLSession两种方式进行信任)
    客户端信任证书的过程:
    1.当客户端要访问服务器的时候,服务器向客户端发送受保护的信任证书
    2.客户端判断是否对客户端发送的证书进行信任,,
    3.如果信任.则客户端会安装公钥在客户端,而服务器就拥有受保护证书的密钥,每一次向服务器请求数据的时候,服务器会先将要发送的数据进行密钥加密,客户端对所传数据通过公钥解密

    下面分享一下自己的经验:

    一开始请求数据先要信任证书,然后才能请求数据,不过对于百度,apple官网这样的大网站就不需要信任证书了,

    只需要信任一次服务器证书

    在信任证书的时候有两种方式:

    大家熟知的有NSURLSession和NSURLConnection两种信任证书的方式,我会重点将第三种:

    如果不信任证书的话会报下面的错误:

    // NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9843)

    // 原因:没有信任证书


    一.NSURLSession的方式信任证书是通过代理的方式:

    1.先懒加载全局的会话:

    @property (nonatomic, strong) NSURLSession *session;
    - (NSURLSession *)session {
        if (_session == nil) {
            NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
            _session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
        }
        return _session;
    }
    
    

    2.发起数据任务
     // url
        NSURL *url = [NSURL URLWithString:@"https://域名"];
        
        // 发起数据任务
        [[self.session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            NSLog(@"%@---%@",response,[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        }] resume];
    
    

    3.代理方法中实现证书的信任-----------
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
    didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
     completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler {
        /*
         <NSURLProtectionSpace: 0x7fef2b686e20>: 
         Host:mail.itcast.cn, 
         Server:https, 
         Auth-Scheme:NSURLAuthenticationMethodServerTrust,
         */
        // 判断是否是信任服务器证书
        if(challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
            // 告诉服务器,客户端信任证书
            // 创建凭据对象
            NSURLCredential *credntial = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            // 通过completionHandler告诉服务器信任证书
            completionHandler(NSURLSessionAuthChallengeUseCredential,credntial);
        }
        NSLog(@"protectionSpace = %@",challenge.protectionSpace);
    }
    
    


    二.NSURLConnection的方式信任证书也是通过代理的方式:

    1.发送请求:
     
        // url
        NSURL *url = [NSURL URLWithString:@"https://mail.itcast.cn"];
        
        // request
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        
        // 发送请求
        [NSURLConnection connectionWithRequest:request delegate:self];
    
    

    2.信任证书
    #pragma mark - NSURLConnectionDataDelegate 代理方法
    - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
        // 判断是否是信任服务器证书
        if(challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
            // 告诉服务器,客户端信任证书
            // 创建凭据对象
            NSURLCredential *credntial = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            // 告诉服务器信任证书
            [challenge.sender useCredential:credntial forAuthenticationChallenge:challenge];
        }
    }
    
    

    3.获取请求到的数据
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
        NSLog(@"data = %@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    }
    
    

    三.AFNetworking的方式信任服务器证书:

    先上代码:
        AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
        manager.securityPolicy.validatesDomainName = NO;
        manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    //    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html", nil];
        [manager GET:@"https://域名" parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
            NSLog(@"%@",downloadProgress);
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            NSLog(@"%@---%@",[responseObject class],responseObject);
            NSLog(@"%@",[[NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding]);
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            NSLog(@"%@",error);
        }];
    
    


    注意解释遇到的坑:
    1.https的协议直接请求的时候会报下面的错:

    NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9843)

    2.设置属性
    不能将validatesDomainName设置为NO,当设置为NO以后可以发出任意的请求,所以要将其设置为YES(默认是YES)-----重点

    manager.securityPolicy.validatesDomainName =YES;

    AFNetworking 的安全相關設定放在 AFSecurityPolicy,它定義了三種 SSL Pinning Mode:

    • AFSSLPinningModeNone : 你不必將憑證跟你的 APP 一起打包,完全信任伺服器的憑證AFSSLPinningModeCertificate : 比對伺服器憑證跟你的憑證是否完全匹配AFSSLPinningModePublicKey : 只比對伺服器憑證的 public key 跟你的憑證的 public key 是否匹配

    那要選用何種模式比較好呢?

    AFSSLPinningModeCertificate 比較安全但也比較麻煩,它會比對你打包的憑證跟伺服器的憑證是否一致。因為你的憑證是跟 APP 一起打包的,這也就代表說如果你的憑證過期了或是變動了,你就得出一版新的 APP 而且舊版 APP 的憑證就失效了。你也可以在每次 APP 啟動時,就自動連到某個伺服器下載最新的憑證,不過此時這個下載連線就會是有風險的。

    AFSSLPinningModePublicKey 則是只有比對憑證裡的 public key,所以即使伺服器憑證有所變動,只要 public key 不變,就能通過驗證。

    所以如果你能確保每個使用者總是使用最新版本的 APP(例如是公司企業內部專用的),那就可以考慮 AFSSLPinningModeCertificate,否則的話選擇 AFSSLPinningModePublicKey 是比較實際的作法。


    解决了证书信任的问题,也就是说设置上面的属性以后就可以信任证书了

    但是问题没有解决:越到了经常遇到的问题,就是请求的数据打印有问题,

    Error Domain=com.alamofire.error.serialization.response Code=-1016 "Request failed: unacceptable content-type: text/html" 

     

    原因:

    这是因为 AFNetworking默认把响应结果当成json来处理,(默认manager.responseSerializer = [AFJSONResponseSerializer serializer]) ,很显然,我们请求的百度首页 返回的并不是一个json文本,而是一个html网页,但是AFNetworking并不知道,它坚信请求的结果就是一个json文本!然后固执地以json的形式去解析,显然没办法把一个网页解析成一个字典或者数组,所以产生了上述错误.

    然而,我们期望它能够正确地处理这个情形,而不是提示一个错误. 
    这时候 你必须告诉AFNetworking:别把这个网页当json来处理! 


    解决办法:

    只需要在发送请求前加入:manager.responseSerializer = [AFHTTPResponseSerializer serializer]

    以上步骤就可以实现https证书的信任和正确的获取例如baidu.com首页的html的源码...

    附加说明:

    网页上加载的数据本质是字符串,我们将获取到的网页数据通过二进制转字符串的形式可以讲网页数据进行打印:

     NSLog(@"%@",[[NSStringalloc]initWithData:responseObjectencoding:NSUTF8StringEncoding]);





     

    有了上面的解决办法是不是不知道如何获取凭证能,别急,下面添加如何获取制定域名的凭证:

    参考链接:

    http://nelson.logdown.com/posts/2015/04/29/how-to-properly-setup-afnetworking-security-connection/

    取得安全憑證

    1. 確認有使用安全連線

    如果你跟遠端伺服器是透過 HTTP 連線,那就不是安全連線,如果是 HTTPS 那就是安全連線。

    2. 準備好網站的安全憑證

    接下來我們需要憑證檔(Certification file),它的副檔名是 .cer,你可以跟你們的網站管理員詢問,通常他們都知道怎麼拿到這個檔案。

    如果你的網站管理員沒有 .cer 檔,只有 .crt 檔,那你可以透過以下這行指令轉檔,要注意的是它是採用 DER 編碼格式(請自行將 myWebsite 替換成你想要的名字):

    openssl x509 -in myWebsite.crt -out myWebsite.cer -outform der

    如果很不幸的,你的網站管理員連 .crt 檔都沒有,那你也可以使用下列這一整行指令從你們的網站取得憑證(請自行將 www.mywebsite.com 替換成你們的網址):

    openssl s_client -connect www.mywebsite.com:443 </dev/null 2>/dev/null | openssl x509 -outform DER > myWebsite.cer

    現在你有一個憑證檔了。

    3. 將憑證加入你的專案

     
    將你的憑證拖拉放到 Xcode 專案底下,記得要把 Copy items if needed 跟 Add to targets 打勾 
  • 相关阅读:
    SpringBoot整合Spring Data Elasticsearch
    Elasticsearch(一)基础入门
    二叉排序树
    数据结构之栈
    数据结构之队列
    MySQL主从备份
    Redis主从复制之哨兵模式(sentinel)
    shiro核心
    MySQL常用命令
    Docker常用命令
  • 原文地址:https://www.cnblogs.com/xsyl/p/6419481.html
Copyright © 2011-2022 走看看