zoukankan      html  css  js  c++  java
  • 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中,提供了身份验证与加密通讯方法

    简单来讲就是一句话: HTTP + SSL = HTTPS

    那 HTTP 和 HTTPS 二者之间到底有什么区别呢 ?
    HTTP(超文本传输协议)协议被用于在Web浏览器和网站服务器之间传递信息。HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此HTTP协议不适合传输一些敏感信息,比如信用卡号、密码等。
    为了解决HTTP协议的这一缺陷,需要使用另一种协议:安全套接字层超文本传输协议HTTPS。为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。

    HTTPS和HTTP的区别主要为以下四点:
    一、https协议需要到ca申请证书,一般免费证书很少,需要交费。
    二、http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。
    三、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
    四、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

    那现在肯定有些人对SSL好奇咯,我们现在看看 SSL能提供一些什么服务呢 ?

    SSL协议提供的服务主要有哪些
    1)认证用户和服务器,确保数据发送到正确的客户机和服务器
    2)加密数据以防止数据中途被窃取
    3)维护数据的完整性,确保数据在传输过程中不被改变。
    SSL协议的工作流程
    服务器认证阶段:
    1)客户端向服务器发送一个开始信息“Hello”以便开始一个新的会话连接;
    2)服务器根据客户的信息确定是否需要生成新的主密钥,如需要则服务器在响应客户的“Hello”信息时将包含生成主密钥所需的信息;
    3)客户根据收到的服务器响应信息,产生一个主密钥,并用服务器的公开密钥加密后传给服务器;
    4)服务器恢复该主密钥,并返回给客户一个用主密钥认证的信息,以此让客户认证服务器。

    那 现在我们来看一下 HTTPS 在使用时 我们在iOS这一块需要做一些什么事情呢 ?

    实现支持HTTPS
    首先,需要明确你使用HTTP/HTTPS的用途,因为OSX和iOS平台提供了多种API,来支持不同的用途,官方文档《Making HTTP and HTTPS Requests》有详细的说明,而文档《HTTPS Server Trust Evaluation》则详细讲解了HTTPS验证相关知识,这里就不多说了。本文主要讲解我们最常用的NSURLConnection支持HTTPS的实现(NSURLSession的实现方法类似,只是要求授权证明的回调不一样而已),以及怎么样使用AFNetworking这个非常流行的第三方库来支持HTTPS。本文假设你对HTTP以及NSURLConnection的接口有了足够的了解。
    验证证书的API
    相关的Api在Security Framework中,验证流程如下:
    1). 第一步,先获取需要验证的信任对象(Trust Object)。这个Trust Object在不同的应用场景下获取的方式都不一样,对于NSURLConnection来说,是从delegate方法-connection:willSendRequestForAuthenticationChallenge:回调回来的参数challenge中获取([challenge.protectionSpace serverTrust])。
    2). 使用系统默认验证方式验证Trust Object。SecTrustEvaluate会根据Trust Object的验证策略,一级一级往上,验证证书链上每一级数字签名的有效性(上一部分有讲解),从而评估证书的有效性。
    3). 如第二步验证通过了,一般的安全要求下,就可以直接验证通过,进入到下一步:使用Trust Object生成一份凭证([NSURLCredential credentialForTrust:serverTrust]),传入challenge的sender中([challenge.sender useCredential:cred forAuthenticationChallenge:challenge])处理,建立连接。
    4). 假如有更强的安全要求,可以继续对Trust Object进行更严格的验证。常用的方式是在本地导入证书,验证Trust Object与导入的证书是否匹配。更多的方法可以查看Enforcing Stricter Server Trust Evaluation,这一部分在讲解AFNetworking源码中会讲解到。
    5). 假如验证失败,取消此次Challenge-Response Authentication验证流程,拒绝连接请求。
    ps: 假如是自建证书的,则会跳过第二步,使用第三部进行验证,因为自建证书的根CA的数字签名未在操作系统的信任列表中。
    iOS授权验证的API和流程大概了解了,下面,我们看看在NSURLConnection中的代码实现:
    使用NSURLConnection支持HTTPS的实现
    // Now start the connection
    NSURL * httpsURL = [NSURL URLWithString:@”https://www.google.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];
      

      }
      }
      上面是代码是通过系统默认验证流程来验证证书的。假如我们是自建证书的呢?这样Trust Object里面服务器的证书因为不是可信任的CA签发的,所以直接使用SecTrustEvaluate进行验证是不会成功。又或者,即使服务器返回的证书是信任CA签发的,又如何确定这证书就是我们想要的特定证书?这就需要先在本地导入证书,设置成需要验证的Anchor Certificate(就是根证书),再调用SecTrustEvaluate来验证。代码如下
      //先导入证书
      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];
      

      }
      }
      建议采用本地导入证书的方式验证证书,来保证足够的安全性。更多的验证方法,请查看官方文档《HTTPS Server Trust Evaluation》

    那 对于熟悉网络请求的同学 对于AFNetworking肯定不会陌生了,它是使用的时候是怎么配置HTTPS的呢?

    AFNetworking上配置对HTTPS的支持非常简单:

    NSURL url = [NSURL URLWithString:@”https://www.google.com“];
    AFHTTPRequestOperationManager 
    requestOperationManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:url];
    dispatch_queue_t requestQueue = dispatch_create_serial_queue_for_name(“kRequestCompletionQueue”);
    requestOperationManager.completionQueue = requestQueue;
    AFSecurityPolicy securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    //allowInvalidCertificates 是否允许无效证书(也就是自建的证书),默认为NO
    //如果是需要验证自建证书,需要设置为YES
    securityPolicy.allowInvalidCertificates = YES;
    //validatesDomainName 是否需要验证域名,默认为YES;
    //假如证书的域名与你请求的域名不一致,需把该项设置为NO
    //主要用于这种情况:客户端请求的是子域名,而证书上的是另外一个域名。因为SSL证书上的域名是独立的,假如证书上注册的域名是www.google.com,那么mail.google.com是无法验证通过的;当然,有钱可以注册通配符的域名
    .google.com,但这个还是比较贵的。
    securityPolicy.validatesDomainName = NO;
    //validatesCertificateChain 是否验证整个证书链,默认为YES
    //设置为YES,会将服务器返回的Trust Object上的证书链与本地导入的证书进行对比,这就意味着,假如你的证书链是这样的:
    //GeoTrust Global CA
    // Google Internet Authority G2
    //  .google.com
    //那么,除了导入
    .google.com之外,还需要导入证书链上所有的CA证书(GeoTrust Global CA, Google Internet Authority G2);
    //如是自建证书的时候,可以设置为YES,增强安全性;假如是信任的CA所签发的证书,则建议关闭该验证;
    securityPolicy.validatesCertificateChain = NO;
    requestOperationManager.securityPolicy = securityPolicy;
    这就是AFNetworking的支持HTTPS的主要配置说明,AFHTTPSessionManager与之基本一致,就不重复了。

    因为HTTPS相比于HTTP来说,会有一些性能上的劣势,但是相对比安全性,就是小巫见大巫了。

    最怕你一生碌碌无为 还安慰自己平凡可贵
  • 相关阅读:
    JS分页条插件
    C#Lambda
    常用CSS样式速查
    简易表格编辑器
    使用template
    js 时间类函数
    数据库表增删查改帮助类
    使用github
    box-shadow属性
    box-sizing属性
  • 原文地址:https://www.cnblogs.com/fakeCoder/p/5093810.html
Copyright © 2011-2022 走看看