iOS - HTTPS

作者: Mitchell | 来源:发表于2015-09-10 20:37 被阅读34866次
    作者:Mitchell 
    

    一、简介


    二、HTTPS与HTTP的区别

    • 这里用两张图来介绍两者的区别:
      • HTTP:当客户端发送请求,那么服务器会直接返回数据。


        HTTP.png
      • HTTPS:当客户端第一次发送请求的时候,服务器会返回一个包含公钥的受保护空间(也成为证书),当我们发送请求的时候,公钥会将请求加密再发送给服务器,服务器接到请求之后,用自带的私钥进行解密,如果正确再返回数据。这就是 HTTPS 的安全性所在。


        HTTPS.png

    三、实例

    #import "ViewController.h"
    @interface ViewController ()<NSURLSessionDataDelegate>
    @end
    @implementation ViewController
     - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSURL *url = [NSURL URLWithString:@"https://kyfw.12306.cn/otn/leftTicket/init"];
    //    NSURL *url = [NSURL URLWithString:@"https://www.apple.com/"];
    //    NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
        NSURLSessionDataTask *task = [session dataTaskWithRequest:request];
        [task resume];
    }
    #pragma mark - NSURLSessionDataDelegate
    /*
    // 只要访问的是HTTPS的路径就会调用
    // 该方法的作用就是处理服务器返回的证书, 需要在该方法中告诉系统是否需要安装服务器返回的证书
    // NSURLAuthenticationChallenge : 授权质问
    //+ 受保护空间
    //+ 服务器返回的证书类型
     - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
    {
    //    NSLog(@"didReceiveChallenge");
    //    NSLog(@"%@", challenge.protectionSpace.authenticationMethod);
        
        // 1.从服务器返回的受保护空间中拿到证书的类型
        // 2.判断服务器返回的证书是否是服务器信任的
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            NSLog(@"是服务器信任的证书");
            // 3.根据服务器返回的受保护空间创建一个证书
    //         void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *)
    //         代理方法的completionHandler block接收两个参数:
    //         第一个参数: 代表如何处理证书
    //         第二个参数: 代表需要处理哪个证书
            //创建证书
            NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            // 4.安装证书   completionHandler(NSURLSessionAuthChallengeUseCredential , credential);    
        }
    }
    */
     - (void)URLSession:(NSURLSession *)session
    didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
     completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
    {
       //AFNetworking中的处理方式
        NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        __block NSURLCredential *credential = nil;  
        //判断服务器返回的证书是否是服务器信任的
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            /*disposition:如何处理证书
         NSURLSessionAuthChallengePerformDefaultHandling:默认方式处理
             NSURLSessionAuthChallengeUseCredential:使用指定的证书    NSURLSessionAuthChallengeCancelAuthenticationChallenge:取消请求
             */
            if (credential) {
                disposition = NSURLSessionAuthChallengeUseCredential;
            } else {
                disposition = NSURLSessionAuthChallengePerformDefaultHandling;
            }
        } else {
            disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
        }
        //安装证书
        if (completionHandler) {
            completionHandler(disposition, credential);
        }
    }
    // 接收到服务器的响应
     - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
    {
        NSLog(@"didReceiveResponse");
        completionHandler(NSURLSessionResponseAllow);
    }
    // 接收到服务器返回的数据
     - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
    {
        NSLog(@"didReceiveData");
    }
    // 请求完毕
     - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
    {
        NSLog(@"didCompleteWithError");
    }
    @end
    

    四、问题

    • 有时采用HTTPS 无法接受数据,是因为苹果将http使用的是TLS 1.2 SSL 加密请求数据,而服务器有的时候使用的还是TLS 1.1
    • 解决办法:在 info.plist 中添加
    • <key>NSAppTransportSecurity</key><dict>
      <key>NSAllowsArbitraryLoads</key>
      <true/></dict>

    打造安全的 APP HTTPS

    相关文章

      网友评论

      • zziazm:“判断服务器返回的证书是否是服务器信任的”这句话怎么理解的
      • lanmoyingsheng:为什么有的文章说:https只在建立连接通过私钥、公钥验证。连接后客户端、服务端使用客户端提供的对称密钥进行通信。:frowning:
        lanmoyingsheng:@charleswang 苹果早就取消了强制https的要求,你在plist文件中加入那个配置就行了。
        charleswang:楼主 我想问个问题 我的App中请求的接口都是https的,但有部分的加载webview的地址不是https的,若在info.plist中配置NSAllowsArbitraryLoads上架会不会有问题?
        chenyu1520:这就是 HTTPS 的精华,你说的几乎全对。
      • younger_times:请问,服务器改为HTTPS前台需要改些什么呢?
        Mitchell:@younger_times 仔细看一下那两篇参考链接
      • Laki只是想做一个程序猿:您好打扰下,服务器那边配置好了https,询问我是否更新服务器,我这边原来是在info.plist里面绕过https使用http请求。我这边需要做什么工作吗?配置服务器?还有一个问题我有点乱,就是https还是ipv6 苹果规定 无法使用ip地址作为请求,只能使用域名? 那要是这样。本地测试数据是ip地址的怎么办? 谢谢博主
        Laki只是想做一个程序猿:@Mitchell 非常感谢
        Mitchell:@Laki只是想做一个程序猿 开发,测试,线上环境,让服务器配一下啊,只有线上环境是对外网的 https,开发和测试环境如果内网 ip 就行,外部能访问再加 http 的域名就行。抱歉比较忙回答比较晚 不知道还能不能帮上忙。
      • Miles_miles:可以可以
      • 简洁的想法:公司是https 接口,但是请求时返回“发生了 SSL 错误,无法建立与该服务器的安全连接。”
        这个昵称就很帅:@凌晨嘻嘻 我记得当初的SSL错误好像是服务端的问题。按照刚刚的文章说法倒腾一遍试试。
        这个昵称就很帅:@凌晨嘻嘻 这篇文章你也看一下,说不定对你有帮助。http://www.jianshu.com/p/f312a84a944c
        adc86fe34b3e:@简洁的想法 朋友 报的这个ssl错误 你们解决了吗 我们现在也遇到了这个问题 希望能回复我一下好吗
      • 这个昵称就很帅:这种是什么错误:- error[发生了 SSL 错误,无法建立与该服务器的安全连接。]
        这个昵称就很帅:@凌晨嘻嘻 这个我记得应该是服务器那边的问题,好像是和证书相关。你客户端代码按照这篇文章写的做,其他就是服务器端的问题了。
        adc86fe34b3e:@这个昵称就很帅 朋友 包的这个ssl错误 你们解决了吗 我们现在也遇到了这个问题 希望能回复我一下好吗
      • 许漠颜:楼主有联系方式能留一下吗?我暂时也在弄有关https这一块有些问题想要请教一下。
      • 阿尔法代码狗:楼主,我们公司服务器是http的,接口也都是,但是现在要接入一个第三方,他们没有sdk,只给了一些接口,都是https的,这个怎么解决,还是在infoplist里面加字段,那样会不会把https关了
        Mitchell:@阿尔法代码狗 HTTPS 正常用就行,第三方的 SDK 应该是第三方认证的证书。抱歉比较忙,回答的比较晚,不知道还能不能帮上什么。
      • 西西西瓜sama:看了图里的代码 相当于只请求下来了服务器的公钥 博主能把接下来的也完成么
      • 73d928a3a8be:http://www.jianshu.com/p/c6a903da8346
        你这里的“ 四、问题”内的阐述,可以看下这里的“4.1 不正确的做法”部分(只是看下,不太确定他的是否正确)。
      • 冰不是水H:图很清晰易懂
      • 南方小金豆:NSAllowsArbitraryLoads 说是让app 支持http的请求,如果api使用了https,设置NSAllowsArbitraryLoads会不会对api请求有影响?
        简单日记:@那份牵挂给了谁 这个应该是服务器的证书和本地证书不匹配
        南方小金豆:@Mitchell 我上次测试https的时候,总是请求报错 -999 ,知道这个是什么原因吗?
        Mitchell:@那份牵挂给了谁 不会。https可以正常发送。
      • 我是韩叫兽:请问如果用AFHTTPSessionManager该如何实现?
        写成下面这样不行吗?
        ```
        AFSecurityPolicy * securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
        ecurityPolicy.allowInvalidCertificates = NO;
        securityPolicy.validatesDomainName = NO;

        AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
        mgr.securityPolicy = securityPolicy;
        [mgr GET:self.urlTextField.text parameters:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
        self.infoLabel.text = @"成功";
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        self.infoLabel.text = [NSString stringWithFormat:@"失败:%@", error.userInfo];
        }];
        ```
      • 我真的真的是文艺青年:自己申请的CA证书如何使用啊

        无忌不悔:@我真的真的是文艺青年 http://www.jianshu.com/p/6b9c8bd5005a

      本文标题:iOS - HTTPS

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