添加HTTPS验证

业务需求需要添加HTTPS请求方式,需要添加自建ca证书,这里做一些设置。

—- 参考文章:iOS9之适配ATS —-

—- 参考文章:SSL/TLS协议运行机制的概述 —-

—- 参考文章:HTTPS的学习总结 主要参考 —-

—- 参考文章:openssl的证书格式转换 里面格式转换inkey是要密码的—-

1.TSL和SSL

TLS 是 SSL 新的别称:

TLS1.0”之于“SSL3.1”,犹“公元2015”之于“民国104”,“一千克”之于“一公斤”:称呼不同,意思相同。

SSL 3.0版本之后的迭代版本被重新命名为TLS 1.0:TLS 1.0=SSL 3.1。所以我们平常也经常见到 “SSL/TLS” 这种说法。

目前,应用最广泛的是TLS 1.0,接下来是SSL 3.0。目前主流浏览器都已经实现了TLS 1.2的支持。

2.ATS是什么

HTTPS = “HTTP over SSL”

Apple让你的HTTP采用SSL/TLS协议,就是让你从HTTP转到HTTPS。而这一做法,官方文档称为ATS,全称为App Transport Security。

研究一下业务需求—–

https 用于远程控制
socket 用于直连控制 ——不涉及https https
第三方登录(微信,QQ)

两种实现方案—-

1.远程控制需要验证https 第三方登录用白名单通过 ,只要有其他需求就要加添加白名单

2.全部可以通过验证,需要HTTPS的写远程控制,添加除外域名,避免每次都要添加白名单

暂定使用第二种解决方案

服务器提供了cer的证书给我—-xcode需要的是p12证书,还需要进一步联调,

/

.cer/.crt是用于存放证书,它是2进制形式存放的,不含私钥。

.pem跟crt/cer的区别是它以Ascii来表示。

pfx/p12用于存放个人证书/私钥,他通常包含保护密码,2进制方式

2 这里的xxx.pem可以和 xxx.cer 、 xxx.p12之间相互转换

openssl x509 -in xxx.pem -outform der -out xxx.cer

openssl x509 -in xxx.pem -outform der -out xxx.12

openssl x509 -in xxx.cer -outform der -out xxx.pem

openssl x509 -in xxx.12 -outform der -out xxx.pem

1

把cer文件或者p12文件加入到里面去
请求链接改成HTTPS

代码处理 参考文章 使用AFN如何访问HTTPS网站:

关键代码—-我们这里需要将证书导入到项目中,所以我选择了第二种方式

// 方式一 两句就可以-----ca证书
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
manager.securityPolicy.validatesDomainName = NO; // 关键语句1
manager.securityPolicy.allowInvalidCertificates = YES; // 关键语句2
[manager GET:@"https://kyfw.12306.cn/otn/leftTicket/init" parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
    NSLog(@"%@", responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
}];


// 方式二 需要将证书导入到项目中----自建证书
// 准备:将证书的二进制读取,放入set中
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"kyfw.12306.cn.cer" ofType:nil];
NSData *cerData = [NSData dataWithContentsOfFile:cerPath];
NSSet *set = [[NSSet alloc] initWithObjects:cerData, nil];

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:set]; // 关键语句1
manager.securityPolicy.allowInvalidCertificates = YES; // 关键语句2
[manager GET:@"https://kyfw.12306.cn/otn/leftTicket/init" parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
    NSLog(@"%@", responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
}];

返回结果失败:

2016-10-08 20:02:21.396 TestYTKNetwork[3840:2276038] CFNetwork SSLHandshake failed (-9847)
2016-10-08 20:02:21.397 TestYTKNetwork[3840:2276038] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9847)
2016-10-08 20:02:31.502 TestYTKNetwork[3840:2274644] Error: Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={_kCFStreamErrorCodeKey=-9847, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, NSUnderlyingError=0x7fdd614a92e0 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, _kCFNetworkCFStreamSSLErrorOriginalValue=-9847, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9847}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://172.16.38.81:8080/moto/app/login.do, NSErrorFailingURLStringKey=https://172.16.38.81:8080/moto/app/login.do, _kCFStreamErrorDomainKey=3}, (null), (null)

CFNetwork SSLHandshake failed (-9847)为关键字 检查了一下,发现是端口错了——-

https访问路径:https://172.16.38.81:8443
http访问路径:http://172.16.38.81:8080

改一下端口

新的报错:

In order to validate a domain name for self signed certificates, you MUST use pinning.

找到原因 —–

参考文章 —– AFN https部分源码解析

if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) {
    // https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html
    //  According to the docs, you should only trust your provided certs for evaluation.
    //  Pinned certificates are added to the trust. Without pinned certificates,
    //  there is nothing to evaluate against.
    //
    //  From Apple Docs:
    //          "Do not implicitly trust self-signed certificates as anchors (kSecTrustOptionImplicitAnchors).
    //           Instead, add your own (self-signed) CA certificate to the list of trusted anchors."
    NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");
    return NO;
}

两个可能性

  1. 是否验证域名—— manager.securityPolicy.validatesDomainName = NO;
  2. 证书不对—-

打断点发现 NSSet为空 —— 证书没有引用成功

原因 :bundle 没有添加到库里面去—

这里写图片描述

加进去 —- NSset有了 —- 跑通了—————-

但是返回结果不对 — 为一串二进制———

Reply JSON: <7b226865 61646572 223a7b22 636f6465 223a302c 22636d64 223a226c 6f67696e 222c226d 73674964 223a2231 32333435 36373839 227d2c22 626f6479 223a7b22 75736572 496e666f 223a7b22 68656164 6572223a 6e756c6c 2c226e69 636b4e61 6d65223a 6e756c6c 2c226765 6e646572 223a6e75 6c6c2c22 70686f6e 65223a22 36222c22 75736572 4964223a 32302c22 6f70656e 4964223a 6e756c6c 2c227265 67697346 726f6d22 3a307d2c 22746f6b 656e223a 2231347c 54565862 434f6248 5764696f 70227d7d>

http可以成功 https确失败了 有可能解码失败—有可能涉及到公钥和私钥的问题

考虑使用P12 证书,因为p12存在私钥

尝试结果一样 因此 P12和cer文件没有影响———-有可能是https没有通过验证—所以返回了一样的结果

Reply JSON: <7b226865 61646572 223a7b22 636f6465 223a302c 22636d64 223a226c 6f67696e 222c226d 73674964 223a2231 32333435 36373839 227d2c22 626f6479 223a7b22 75736572 496e666f 223a7b22 68656164 6572223a 6e756c6c 2c226e69 636b4e61 6d65223a 6e756c6c 2c226765 6e646572 223a6e75 6c6c2c22 70686f6e 65223a22 36222c22 75736572 4964223a 32302c22 6f70656e 4964223a 6e756c6c 2c227265 67697346 726f6d22 3a307d2c 22746f6b 656e223a 2231347c 42437032 436b4d35 614d6b4d 5a227d7d>

猜测是需要JSON转字典的问题

增加一行代码:

            if (responseObject) {
                NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:responseObject options:(NSJSONReadingMutableLeaves) error:nil];

                NSLog(@"%@",dict);
            }

再次运行:

跑通:

打印结果:

Printing description of dict:
{
    body =     {
        token = "14|7dCA7SMxVWqcO";
        userInfo =         {
            gender = "<null>";
            header = "<null>";
            nickName = "<null>";
            openId = "<null>";
            phone = 6;
            regisFrom = 0;
            userId = 20;
        };
    };
    header =     {
        cmd = login;
        code = 0;
        msgId = 123456789;
    };
}
Printing description of response:
<NSHTTPURLResponse: 0x7f83c160e840> { URL: https://172.16.38.81:8443/moto/app/login.do } { status code: 200, headers {
    "Content-Type" = "application/json;charset=UTF-8";
    Date = "Sun, 09 Oct 2016 01:41:26 GMT";
    Server = "Apache-Coyote/1.1";
    "Set-Cookie" = "JSESSIONID=B4E5D68D42490EE213E54ED1D2C3FC36; Path=/moto/; Secure; HttpOnly";
    "Transfer-Encoding" = Identity;
} }

这里写一下出现这种情况的原因:

AFN帮助HTTP做了很多优化,如果是JSON会帮你转换成字典—-
HTTPS没有做这些操作 —– 所以需要判断一下如果是HTTPS就转换 —-
具体的判断可以判断 Response的URL 是不是HTTPS的请求—-

最后是代码部分 ———-

- (void)AFNLogin {

    //请求体
    NSMutableDictionary *params = [NSMutableDictionary dictionary];

    //manager管理类
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

    //请求方式和服务器地址
    NSMutableURLRequest *req = [[AFJSONRequestSerializer serializer] requestWithMethod:@"POST" URLString:@"https://xxxxxx" parameters:nil error:nil];



    //请求头
    [req setValue:@"application/mjson;charset=UTF-8" forHTTPHeaderField:@"Content-Type"];

    //请求体
    [req setHTTPBody:[NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:nil]];

    //证书
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"ca.cer" ofType:nil];
    NSData *cerData = [NSData dataWithContentsOfFile:cerPath];
    NSSet *set = [[NSSet alloc] initWithObjects:cerData, nil];


    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    //变更签名方式为证书验证----
    manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:set];
    //允许无效的证书(非ca颁发的---自建证书)
    manager.securityPolicy.allowInvalidCertificates = YES;
    //是否验证域名------
//    manager.securityPolicy.validatesDomainName = NO;



    //开始请求
    [[manager dataTaskWithRequest:req completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {

        if (!error) {
            NSLog(@"Reply JSON: %@", responseObject);

            //如果为HTTPS请求
            if (responseObject) {
                NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:responseObject options:(NSJSONReadingMutableLeaves) error:nil];

                NSLog(@"%@",dict);
            }

        } else {

            NSLog(@"Error: %@, %@, %@", error, response, responseObject);


        }
    }] resume];

}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值