上文介紹了HTTP協(xié)議篮奄,本文介紹一下HTTPS協(xié)議悴能。
1. 什么是HTTPS
HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer)景馁,是以安全為目標的HTTP通道,簡單講是HTTP的安全版刑巧,即HTTP下加入SSL層顽照。HTTPS的安全基礎是SSL,因此加密的詳細內(nèi)容就需要SSL辽装,它是一個URI scheme(抽象標識符體系)帮碰,句法類同http:體系,用于安全的HTTP數(shù)據(jù)傳輸拾积。
https:URL表明它使用了HTTP殉挽,但HTTPS存在不同于HTTP的默認端口及一個加密/身份驗證層(在HTTP與TCP之間)。
HTTPS = HTTP + 加密 + 認證 + 完整性保護拓巧,其實HTTPS是身披SSL外殼的HTTP斯碌。
2. HTTPS和HTTP的區(qū)別主要為以下四點:
- https協(xié)議需要到ca申請證書,一般免費證書很少玲销,需要交費输拇。
- http是超文本傳輸協(xié)議摘符,信息是明文傳輸贤斜,https 則是具有安全性的ssl加密傳輸協(xié)議。
- http和https使用的是完全不同的連接方式逛裤,用的端口也不一樣瘩绒,前者是80,后者是443带族。
- http的連接很簡單锁荔,是無狀態(tài)的;HTTPS協(xié)議是由SSL+HTTP協(xié)議構建的可進行加密傳輸蝙砌、身份認證的網(wǎng)絡協(xié)議阳堕,比http協(xié)議安全跋理。
3. HTTPS的通信過程
當客戶端發(fā)送數(shù)據(jù)請求的時候客戶端不會馬上返回響應數(shù)據(jù),而是創(chuàng)建一個安全證書恬总,然后把安全證書給客戶端安裝前普,安裝之后,客戶端和服務端就創(chuàng)建了一個受保護的空間通道壹堰,服務器端有公鑰和私鑰拭卿,公鑰發(fā)給客戶端,留著客戶端加密數(shù)據(jù)用贱纠,私鑰服務端留著峻厚,用來解密客戶端發(fā)來的信息,然后響應完成谆焊。
HTTPS = HTTP + SSL(Secure socket layer惠桃,安全套接字層)
4. HTTPS工作原理詳細過程
HTTPS工作在客戶端和服務器端之間“枚桑客戶端和服務器本身都會自帶一些加密的算法刽射,用于雙方協(xié)商加密的選擇項。
- 客戶端首先會將自己版本號剃执,支持的加密算法等誓禁,打個包告訴服務器端。
- 服務器端從客戶端發(fā)來的加密算法中肾档,選出一組加密算法和HASH算法(注:HASH也屬于加密)摹恰,并將自己的身份信息以證書的形式發(fā)回給客戶端,證書中包含了網(wǎng)站的地址怒见,加密用的公鑰俗慈,以及證書的頒發(fā)機構等。
這里遣耍,服務器就將自己用來加密用的公鑰一同發(fā)給客戶端闺阱,而私鑰則服務器保存著,用戶解密客戶端加密過后的內(nèi)容舵变。 - 客戶端收到了服務器發(fā)來的數(shù)據(jù)包后酣溃,會做這么幾件事情:
① 驗證一下證書是否合法。一般來說纪隙,證書是用來標示一個站點是否合法的標志赊豌,如果說該證書由權威的第三方頒發(fā)和簽名的,則說明證書合法绵咱。
② 如果證書合法碘饼,或者客戶端接受和信任了不合法的證書,則客戶端就會隨機產(chǎn)生一串序列號,使用服務器發(fā)來的公鑰進行加密艾恼。這時候住涉,一條返回的消息就基本就緒。
③ 最后使用服務器挑選的HASH算法钠绍,將剛才的消息使用剛才的隨機數(shù)進行加密秆吵,生成相應的消息校驗值,與剛才的消息一同發(fā)還給服務器五慈。 - 服務器接受到客戶端發(fā)來的消息后纳寂,會做這么幾件事情:
① 使用私鑰解密上面第3-②中公鑰加密的消息,得到客戶端產(chǎn)生的隨機序列號泻拦。
② 使用該隨機序列號毙芜,對該消息進行加密,驗證的到的校驗值是否與客戶端發(fā)來的一致争拐,如果一致則說明消息未被篡改腋粥,可以信任。
③ 最后架曹,使用該隨機序列號隘冲,加上之前第2步中選擇的加密算法,加密一段握手消息绑雄,發(fā)還給客戶端展辞,同時HASH值也帶上。 - 客戶端收到服務器端的消息后万牺,接著做這么幾件事情:
① 計算HASH值是否與發(fā)的消息一致
② 檢查消息是否為握手消息 - 握手結束后罗珍,客戶端和服務器端使用握手階段產(chǎn)生的隨機數(shù)以及挑選出來的算法進行對稱加解密的傳輸。
為什么不直接全程使用非對稱加密算法進行數(shù)據(jù)傳輸脚粟?這個問題的答案是因為非對稱算法的效率對比起對稱算法來說覆旱,要低得多得多,因此往往只用在HTTPS的握手階段核无。
5. 其他說明
- HTTPS的主要思想是在不安全的網(wǎng)絡上創(chuàng)建一安全信道扣唱,并可在使用適當?shù)募用馨头掌髯C書可被驗證且可被信任時,對竊聽和中間人攻擊提供合理的保護团南。
- HTTPS的信任繼承基于預先安裝在瀏覽器中的證書頒發(fā)機構(如VeriSign噪沙、Microsoft等)(意即“我信任證書頒發(fā)機構告訴我應該信任的”)。
- 因此已慢,一個到某網(wǎng)站的HTTPS連接可被信任曲聂,如果服務器搭建自己的https 也就是說采用自認證的方式來建立https信道霹购,這樣一般在客戶端是不被信任的佑惠。
- 所以我們一般在瀏覽器訪問一些https站點的時候會有一個提示,問你是否繼續(xù)。
6. 對iOS開發(fā)的影響
#import "ViewController.h"
#import "AFNetworking.h"
@interface ViewController ()<NSURLSessionDataDelegate>
@end
@implementation ViewController
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self afn];
}
-(void)afn
{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
//更改解析方式
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
//設置對證書的處理方式
manager.securityPolicy.allowInvalidCertificates = YES;
manager.securityPolicy.validatesDomainName = NO;
[manager GET:@"https://kyfw.12306.cn/otn" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"success---%@",[[NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"error---%@",error);
}];
}
-(void)session
{
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
NSURL *url = [NSURL URLWithString:HttpsURL];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
request.HTTPMethod = @"POST";
NSString *bodyStr = @"clientversion=6.0&clienttype=2";
request.HTTPBody = [bodyStr dataUsingEncoding:NSUTF8StringEncoding];
NSURLSessionTask *task = [session dataTaskWithRequest:request];
[task resume];
}
#pragma mark NSURLSessionDataDelegate
//如果發(fā)送的請求是https的,那么才會調(diào)用該方法
-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{
if(![challenge.protectionSpace.authenticationMethod isEqualToString:@"NSURLAuthenticationMethodServerTrust"])
{
return;
}
NSLog(@"%@",challenge.protectionSpace);
//NSURLSessionAuthChallengeDisposition枚舉 如何處理證書
/*
NSURLSessionAuthChallengeUseCredential = 0, 使用該證書 安裝該證書
NSURLSessionAuthChallengePerformDefaultHandling = 1, 默認采用的方式,該證書被忽略
NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, 取消請求,證書忽略
NSURLSessionAuthChallengeRejectProtectionSpace = 3, 拒絕
*/
//生成一個無條件信任的credential
NSURLCredential *credential = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];
//NSURLCredential 授權信息
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
}
@end
如果使用了系統(tǒng)的NSURLSession進行數(shù)據(jù)請求膜楷,只要請求的地址是HTTPS的旭咽,就會調(diào)用didReceiveChallenge:這個代理方法,我們需要在該方法中告訴系統(tǒng)赌厅,是否信任服務器返回的證書穷绵,上面的方法直接使用無條件信任了。
如果是使用AFN框架特愿,那么我們不需要做任何額外的操作仲墨,因為AFN內(nèi)部已經(jīng)做了處理。
AFN驗證的源碼如下:
/*
兩種方式: 本地證書驗證 (需要驗證本地證書)
1 驗證服務器
2 本地證書生成NSURLCredential對象揍障,代理回調(diào)block來處理相關事務
無本地證書驗證NSURLAuthenticationMethodServerTrust(直接信任服務器)
1 驗證服務器
2 直接通過服務器傳過來的challenge 生成NSURLCredential對象(這個對象關聯(lián)了客戶端https相關信息)目养,代理回調(diào)block來處理相關事務
*/
// 驗證來源是否有效
- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
__block NSURLCredential *credential = nil;
// 兩種方式 1 外部處理NSURLSessionAuthChallengeDisposition 2 AF內(nèi)部默認處理它
if (self.sessionDidReceiveAuthenticationChallenge) {// 1外部(你自己處理)
disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential);
} else {// 2內(nèi)部(AF處理)
// challenge 服務器過來的,方式(NSURLAuthenticationMethodServerTrust)毒嫡,是否要本地驗證
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
//內(nèi)部三種驗證方式 1 無條件信任 2 證書驗證 3 公約驗證
if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) { // 驗證邏輯
// 返回YES癌蚁,server是沒問題的
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];// 生成一個信任的NSURLCredential對象
if (credential) {
//Use the specified credential
disposition = NSURLSessionAuthChallengeUseCredential;
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
} else {
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
}
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
}
if (completionHandler) {
completionHandler(disposition, credential);
}
}