美文网首页HTTPS
关于HTTPS的那些事

关于HTTPS的那些事

作者: 甘邦 | 来源:发表于2017-05-03 18:19 被阅读53次

    iOS中集成HTTPS

    证书是自签名的HTTPS证书,如果是CA认证的就不会有下面的事情了。项目组最后到阿里云去申请免费试用一年的HTTPS证书。下面的纯属是为了纪念曾经折腾过的问题:

    NSURLSession验证HTTPS

    首先要成为NSURLSession的代理
    <pre>
    NSString *urlString = @"https://xxxx";
    NSURL *myUrl = [NSURL URLWithString:urlString];

    NSMutableURLRequest *myRequest = [NSMutableURLRequest requestWithURL:myUrl cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0f];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    
    NSURLSessionDataTask *task = [session dataTaskWithRequest:myRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    }];
    [task resume];
    

    </pre>
    然后实现下面的代理方法
    <pre>
    /*

    • 代理方法 NSURLSessionDelegate
      */
    • (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
      NSLog(@"证书认证开始..");
      //先导入证书
      NSString * cerPath = [[NSBundle mainBundle] pathForResource:@"你的证书名字" ofType:@"cer"]; //证书的路径
      NSData * cerData = [NSData dataWithContentsOfFile:cerPath];
      SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(cerData));
      NSArray * trustedCertificates = @[CFBridgingRelease(certificate)];
      //1)获取trust object
      SecTrustRef trust = challenge.protectionSpace.serverTrust;
      SecTrustResultType result;
      //注意:这里将之前导入的证书设置成下面验证的Trust Object的anchor certificate
      SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)trustedCertificates);
      //2)SecTrustEvaluate会查找前面SecTrustSetAnchorCertificates设置的证书或者系统默认提供的证书,对trust进行验证
      OSStatus status = SecTrustEvaluate(trust, &result);
      if (status == errSecSuccess &&
      (result == kSecTrustResultProceed ||
      result == kSecTrustResultUnspecified)) {
      NSLog(@"验证成功..");
      //3)验证成功,生成NSURLCredential凭证cred,告知challenge的sender使用这个凭证来继续连接
      NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
      [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];completionHandler(NSURLSessionAuthChallengeUseCredential,cred);
      } else {
      NSLog(@"验证失败..");
      [challenge.sender cancelAuthenticationChallenge:challenge];
      }
      }
      </pre>

    AFNetWorking

    我们先封装出来一个Post方法,设置AFN的setSecurityPolicy方法
    <pre>
    /**

    • pots方法
      */
    • (void)post:(NSString *)url params:(NSDictionary *)params success:(void (^)(id))success failure:(void (^)(NSError *))failure
      {
      // 1.获得请求管理者
      AFHTTPSessionManager *mgr = [[AFHTTPSessionManager manager] initWithBaseURL:[NSURL URLWithString:BaseUrl]];
      // 2.申明返回的结果是text/html类型

      mgr.responseSerializer = [AFHTTPResponseSerializer serializer];

      // 加上这行代码,https ssl 验证。
      [mgr setSecurityPolicy:[self customSecurityPolicy]];

      // 3.发送POST请求
      [mgr POST:url parameters:params progress:nil success:^(NSURLSessionDataTask * task, id responseObject) {
      if (success) {
      success(responseObject);
      }
      } failure:^(NSURLSessionDataTask * task, NSError * error) {
      if (failure) {
      failure(error);
      }
      }];
      }
      </pre>

    自定义的customSecurityPolicy方法:
    <pre>

    • (AFSecurityPolicy*)customSecurityPolicy
      {
      // /先导入证书
      NSString *cerPath = [[NSBundle mainBundle] pathForResource:CertName ofType:@"cer"];//证书的路径
      NSData *certData = [NSData dataWithContentsOfFile:cerPath];

      // AFSSLPinningModeCertificate 使用证书验证模式
      AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];

      // allowInvalidCertificates 是否允许无效证书(也就是自建的证书),默认为NO
      // 如果是需要验证自建证书,需要设置为YES
      securityPolicy.allowInvalidCertificates = YES;

      //validatesDomainName 是否需要验证域名,默认为YES;
      //假如证书的域名与你请求的域名不一致,需把该项设置为NO;如设成NO的话,即服务器使用其他可信任机构颁发的证书,也可以建立连接,这个非常危险,建议打开。
      //置为NO,主要用于这种情况:客户端请求的是子域名,而证书上的是另外一个域名。因为SSL证书上的域名是独立的,假如证书上注册的域名是www.google.com,那么mail.google.com是无法验证通过的;当然,有钱可以注册通配符的域名*.google.com,但这个还是比较贵的。
      //如置为NO,建议自己添加对应域名的校验逻辑。
      securityPolicy.validatesDomainName = NO;

      NSSet *set = [[NSSet alloc] initWithObjects:certData, nil];

      securityPolicy.pinnedCertificates = set;

      return securityPolicy;
      }
      </pre>

    完成!

    相关文章

      网友评论

        本文标题:关于HTTPS的那些事

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