技能闪充--Https

HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。

最少必要知识

1.对称加密

对称加密(也叫私钥加密)指加密和解密使用相同密钥的加密算法。有时又叫传统密码算法,就是加密密钥能够从解密密钥中推算出来,同时解密密钥也可以从加密密钥中推算出来。而在大多数的对称算法中,加密密钥和解密密钥是相同的,所以也称这种加密算法为秘密密钥算法或单密钥算法。

2.非对称加密

与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey);并且加密密钥和解密密钥是成对出现的。非对称加密算法在加密和解密过程使用了不同的密钥,非对称加密也称为公钥加密,在密钥对中,其中一个密钥是对外公开的,所有人都可以获取到,称为公钥,其中一个密钥是不公开的称为私钥。

3.非对称加密的特性

  • 对于一个公钥,有且只有一个对应的私钥。
  • 公钥是公开的,并且不能通过公钥反推出私钥。
  • 通过私钥加密的密文只能通过公钥能解密,通过公钥加密的密文也只能通过私钥能解密。

通过公钥是极难推算出私钥的,只能通过穷举,所以只要密钥足够长,要想从公钥推算出私钥几乎不可能的。

非对称加密的主要用途

对信息保密,防止中间人攻击:将明文使用公钥加密,传输给接收者,这样确保信息只能被有私钥的拥有者解密,其他人无法获得明文信息,因为没有私钥无法进行解密。该方法一般用于交换对称密钥。
身份验证和防止信息篡改:私钥拥有者使用私钥加密一段授权明文,并将授权明文和加密后的密文,以及公钥一并发送出来,接收方只需要通过公钥将密文解密后与授权明文对比是否一致,就可以判断明文在中途是否被篡改过。此方法用于数字签名。

4.摘要算法

摘要算法是一个神奇的算法,也称为散列或者散列值。是一种与基于密钥(对称密钥或公钥)的加密不同的数据转换类型。散列就是通过把一个叫做散列算法的单向数学函数应用于数据,将任意长度的一块数据转换为一个定长的、不可逆转的数字,其长度通常在128~256位之间。所产生的散列值的长度应足够长,因此使找到两块具有相同散列值的数据的机会很少。

摘要算法具有以下特性:
  • 只要源文本不同,计算得到的结果,必然不同(或者说机会很少)。
  • 无法从结果反推出源数据(那是当然的,不然就能量不守恒了)。

5.数字签名

数字签名就是对非对称加密和摘要算法的一种应用,能够确保信息在发布后不会被篡改(摘要算法特性),保证数据的完整性和可信性;同时也可以防止数据被他人伪造(非对称加密算法特性);列如,我们有一段授权文本需要发布时,为了防止中途篡改发布的内容,保证发布文本的完整性,以及文本是由指定的发布者发布的。那么,可以通过摘要算法得到发布内容的摘要,得到摘要之后,发布者使用私钥加密得到密文(签名),这时候将源文本、密文(签名)以及公钥一起发布出去即可。
验证过程为:首先验证公钥是否是发布者的公钥,然后用公钥对密文进行解密,得到摘要,使用发布者对文本同样的摘要算法得到摘要文本,比对摘要是否一致即可确认信息是否被篡改或者是指定发布者发布的。


技能闪充--Https_第1张图片
数字签名

6.现实生活中的证书

在现实生活中,证书顾名思义,就是权限机构颁发的证明。比如英语6级证书,就是教育部门颁发给通过了6级考核的个人的证明,证明这个人的英语能力。我们来看一下这个证书的组成:

被证明人:ZL
内容:通过了英语六级
盖章:教育部门的公章或钢印
当ZL用这张证书找工作时,用人单位会通过查看证书的各项内容(尤其是公章),来验证证书的合法性和ZL的能力。在现实生活中经常有假的6级证书,这些假证书最重要的就是有一个假公章。现实生活中使用法律法规来约束私刻假公章的行为,但是用人单位可能不能十分准确的判断公章是真是假。而数字签字可以来解决该类问题。


技能闪充--Https_第2张图片
数字证书

数字证书的验证

申请证书是为了验证,比如Web应用相关的SSL证书验证方是浏览器,iOS各种证书的验证方是iOS设备。因为数字证书是基于数字签名的,所有数字证书的合法性验证就是验证数字证书的签名是否正确,对于签名的验证在是需要签发机构的公钥才能验证;

正式理解Https

在此前,我们从普通的聊天开始。

如何做到A发给B的消息包,即使被中间人拦截了,也无法得知消息的内容?
技能闪充--Https_第3张图片
e.....

采用对称加密,只要k不公开给第三方,且k足够安全。
技能闪充--Https_第4张图片
对称加密

但是网络环境,这种情况无异于没有加密。


技能闪充--Https_第5张图片
加密

那就需要对不同的客户端使用不同的对称加密算法:
技能闪充--Https_第6张图片
加密

那么就需要服务器和客户端协商使用的对称加密算法,但是协商的过程中,如果被中间人拦截,那和裸奔也没什么区别。
那么就需要采用非对称加密
技能闪充--Https_第7张图片
非对称

那么客户端在向服务器请求公钥的时候,公钥被调包了怎么办?


技能闪充--Https_第8张图片
问题

显然浏览器不可能保存所有网站的公钥。
那么就需要第三方机构的公钥解决这个问题


技能闪充--Https_第9张图片
屏幕快照 2018-05-30 下午7.43.03.png

但是第三方机构不可能只给你一家公司制作证书,所以也可能给“坏公司制作证书”。那它依然有机会对你的证书进行调包,客户端在此时无法分辨接受的是你的证书,还是“中间人”的,因为不论是你的证书还是中间人的证书,都能使用第三方机构的公钥进行解密,拿到公钥:

技能闪充--Https_第10张图片

那么导致的结果就是


技能闪充--Https_第11张图片

那么,解决统一机构颁发的不同证书被篡改的问题,就是客户端的事情。我们从现实中找灵感。比如你是HR,你手上拿到候选人的学历证书,证书上写了持证人,颁发机构,颁发时间等等,同时证书上,还写有一个最重要的:证书编号!我们怎么鉴别这张证书是的真伪呢?只要拿着这个证书编号上相关机构去查,如果证书上的持证人与现实的这个候选人一致,同时证书编号也能对应上,那么就说明这个证书是真实的。
比如,苹果的证书,我没对其进行编码得到的与证书指纹相匹配,说明,证书为真。


技能闪充--Https_第12张图片
证书指纹信息
编码结果

NSURLSession发送和接收

 NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    
    
    NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        NSLog(@"====》%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
        
    }];
    
    [task resume];

NSURLSessionDelegate方法

/*
 challenge :询问,询问客户端是否需要信任来自服务器的证书
 protectionSpace 受保护的空间
 
 completionHandler:通过代码块回调,决定对证书的处理!
 
    NSURLSessionAuthChallengeUseCredential = 0, 使用服务器发回的证书,并且保存到challenge 中
    NSURLSessionAuthChallengePerformDefaultHandling = 1,默认处理方式,会忽略证书
    NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, 取消整个请求,并忽略证书
    NSURLSessionAuthChallengeRejectProtectionSpace = 3,本次拒绝,下次再试


 */
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler
{
    
    //1.判断服务器的身份验证是,信任服务器证书
    //NSLog(@"%s",__FUNCTION__);
    NSLog(@"%@",challenge.protectionSpace);
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        
        //2.获取证书
        NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];

        
        //3.对服务器的证书来进行处理
        completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
        
        
        NSLog(@"是服务器信任!");
    }
    
}

请求结果








    
    

AFN 发送以及请求

 // 1.获得请求管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    // 2.加上这个函数,https ssl 验证。
    [manager setSecurityPolicy:[self customSecurityPolicy]];
//3.AFN默认返回的是json,因为返回的不是JSON,所以。
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager GET:@"https://www.apple.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
//返回的数据被序列化为data,所以我们对数据进行UTF8的编码
        NSLog(@"---->%@",[[NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding]);

    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"->%@",error);
    }];
- (AFSecurityPolicy *)customSecurityPolicy {
    
    // 先导入证书 证书由服务端生成,具体由服务端人员操作
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"www.apple.com.cer" ofType:@"cer"];//证书的路径
    NSData *cerData = [NSData dataWithContentsOfFile:cerPath];
    //使用这个是有问题的
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy];
//    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;
    
//    securityPolicy.pinnedCertificates = [[NSSet alloc] initWithObjects:cerData, nil nil];
    securityPolicy.pinnedCertificates = [[NSSet alloc] initWithObjects:cerData, nil];
    
    return securityPolicy;
}

参考链接:

  • 也许,这样理解HTTPS更容易
  • 数字证书的基础知识

你可能感兴趣的:(技能闪充--Https)