HTTPS定義
- 全稱(chēng):Hypertext Transfer Protocol over Secure Socket Layer
- HTTP的安全版瞧毙,即HTTP之下TCP之上加入SSL層喷好,與HTTP不同的是不同的默認(rèn)端口(http通常是80湿诊,https通常是443)及一個(gè)加密/身份驗(yàn)證層
- HTTPS協(xié)議需要到CA申請(qǐng)證書(shū)妖混,免費(fèi)證書(shū)很少萍恕,需要交費(fèi)
- HTTP的連接是無(wú)狀態(tài)的境氢;HTTPS協(xié)議包含一種類(lèi)似握手協(xié)議的身份認(rèn)證過(guò)程(認(rèn)證是單向的/雙向的)
有兩種基本的加解密算法類(lèi)型
-
對(duì)稱(chēng)加密:密鑰只有一個(gè)蟀拷,加密解密為同一個(gè)密碼碰纬,且加解密速度快,典型的對(duì)稱(chēng)加密算法有DES问芬、AES等悦析;
- 類(lèi)似傳統(tǒng)的賬號(hào)密碼概念,內(nèi)容是賬號(hào)密碼是密鑰
-
非對(duì)稱(chēng)加密:密鑰成對(duì)出現(xiàn)此衅,且根據(jù)公鑰無(wú)法推知私鑰强戴,根據(jù)私鑰也無(wú)法推知公鑰;加密解密使用不同密鑰挡鞍,公鑰加密需要私鑰解密骑歹,私鑰加密需要公鑰解密,如RSA墨微。
- 密文 S = A×B道媚,S是加密后的內(nèi)容,A與B分別是兩個(gè)大素?cái)?shù)(僅可被自己與1整除欢嘿,如13)衰琐,這樣使用A加密后的結(jié)果S只能被B除盡(解開(kāi)),反之同理炼蹦。
有兩種認(rèn)證方法(單向/雙向)
-
單向認(rèn)證:一般意義的https羡宙,如瀏覽器訪(fǎng)問(wèn)https網(wǎng)站
- 主要保證服務(wù)器是它自己所聲明的正確地址
- 客戶(hù)端和服務(wù)端的內(nèi)容都是通過(guò)對(duì)稱(chēng)密鑰加密的
- 對(duì)稱(chēng)密鑰是由客戶(hù)端產(chǎn)生,通過(guò)服務(wù)器派發(fā)出的公鑰加密后發(fā)送給服務(wù)器
-
雙向認(rèn)證:客戶(hù)端也具有一個(gè)自己的證書(shū)掐隐,如銀行的U盾
- 客戶(hù)端本身具備證書(shū)狗热,保密的是傳輸過(guò)程本身而不一定能保證服務(wù)器本身是安全的
- 如常見(jiàn)的釣魚(yú)網(wǎng)站或DNS劫持,用戶(hù)訪(fǎng)問(wèn)的域名并沒(méi)有指向正確的地址虑省,所以客戶(hù)端證書(shū)本身并無(wú)法確保服務(wù)器是真實(shí)的
- 雙向認(rèn)證是指客戶(hù)端不僅要向CA驗(yàn)證服務(wù)器本身的真實(shí)性匿刮,服務(wù)器在響應(yīng)數(shù)據(jù)時(shí)也要驗(yàn)證接收方的真實(shí)性
- 詳細(xì)鏈接 Https detail
證書(shū)格式以及轉(zhuǎn)化
證書(shū)的標(biāo)準(zhǔn)
PKCS 全稱(chēng)是 Public-Key Cryptography Standards
是由 RSA 實(shí)驗(yàn)室與其它安全系統(tǒng)開(kāi)發(fā)商為促進(jìn)公鑰密碼的發(fā)展而制訂的一系列標(biāo)準(zhǔn)
PKCS 目前共發(fā)布過(guò) 15 個(gè)標(biāo)準(zhǔn)。
常見(jiàn)的標(biāo)準(zhǔn):
- PKCS#7 Cryptographic Message Syntax Standard
- PKCS#10 Certification Request Standard
- PKCS#12 Personal Information Exchange Syntax Standard
- X.509是常見(jiàn)通用的證書(shū)格式探颈。所有的證書(shū)都符合為Public Key Infrastructure (PKI) 制定的 ITU-T X509 國(guó)際標(biāo)準(zhǔn)熟丸。
PKCS#7 常用的后綴是: .P7B .P7C .SPC
PKCS#12 常用的后綴有: .P12 .PFX
X.509 DER 編碼(ASCII)的后綴是: .DER .CER .CRT
X.509 PAM 編碼(Base64)的后綴是: .PEM .CER .CRT
編碼與擴(kuò)展名
X.509證書(shū)是一個(gè)數(shù)字文檔,具有擴(kuò)展名和編碼兩個(gè)屬性
- .DER = DER是一種編碼伪节,擴(kuò)展名有三種光羞。以二進(jìn)制存放,常見(jiàn)于Windows系統(tǒng)
- .PEM = PEM是一種編碼怀大,擴(kuò)展名也是三種纱兑,文件開(kāi)始由一行"—– BEGIN …“開(kāi)始。
- .CRT = CRT常見(jiàn)于Linux/Unix證書(shū)化借。證書(shū)可以是DER編碼潜慎,也可以是PEM編碼。
- .CER = CRT證書(shū)的微軟型式。也可以用兩種編碼铐炫。
- .KEY = 擴(kuò)展名KEY用于PCSK#8的公鑰和私鑰垒手。可以是兩種編碼驳遵。
- 擴(kuò)展名CER和CRT幾乎是同義詞淫奔,CRT文件和CER文件只有在使用相同編碼的時(shí)候才可以通過(guò)改后綴名代替。
證書(shū)之間的轉(zhuǎn)換
只有編碼相同可以通過(guò)改后綴名代替堤结,正常情況下應(yīng)該通過(guò)專(zhuān)業(yè)的編碼工具來(lái)互相轉(zhuǎn)換,如OpenSSL
"openssl x509 -in 你的證書(shū).crt -out 你的證書(shū).cer -outform der"
CA簽名證書(shū)與自簽名證書(shū)
CA簽名證書(shū)如何驗(yàn)證
HTTPS連接建立過(guò)程大致是:
- 客戶(hù)端和服務(wù)端建立一個(gè)連接
- 服務(wù)端返回一個(gè)證書(shū)
- 客戶(hù)端里存有各個(gè)受信任的證書(shū)機(jī)構(gòu)根證書(shū)(IOS8 預(yù)裝的根證書(shū)Apple Support
) - 用這些根證書(shū)對(duì)服務(wù)端返回的證書(shū)進(jìn)行驗(yàn)證鸭丛,經(jīng)驗(yàn)證如果證書(shū)是可信任的竞穷,就生成一個(gè)pre-master secret
- 用這個(gè)證書(shū)的公鑰加密后發(fā)送給服務(wù)端,服務(wù)端用私鑰解密后得到pre-master secret
- 再根據(jù)某種算法生成master secret
- 客戶(hù)端也同樣根據(jù)這種算法從pre-master secret生成master secret
- 隨后雙方的通信都用這個(gè)master secret對(duì)傳輸數(shù)據(jù)進(jìn)行加密解密鳞溉。
自簽名的證書(shū)通過(guò)SSL Pinning使用
- 為什么要用SSL Pinning瘾带?
如果服務(wù)端的證書(shū)是從受信任的的CA機(jī)構(gòu)頒發(fā)的,驗(yàn)證是沒(méi)問(wèn)題的熟菲,但CA機(jī)構(gòu)頒發(fā)證書(shū)比較昂貴看政,小企業(yè)或個(gè)人用戶(hù) 可能會(huì)選擇自己頒發(fā)證書(shū),這樣就無(wú)法通過(guò)系統(tǒng)受信任的CA機(jī)構(gòu)列表驗(yàn)證這個(gè)證書(shū)的真?zhèn)瘟顺保孕枰猄SL Pinning這樣的方式去驗(yàn)證允蚣。
- 什么是SSL Pinning?
可以理解為證書(shū)綁定呆贿,是指客戶(hù)端直接保存服務(wù)端的證書(shū)(存入Xcode工程)嚷兔,建立https連接時(shí)直接對(duì)比服務(wù)端返回的和客戶(hù)端保存的兩個(gè)證書(shū)是否一樣,一樣就表明證書(shū)是真的做入,不再去系統(tǒng)的信任證書(shū)機(jī)構(gòu)里尋找驗(yàn)證冒晰。
這適用于非瀏覽器應(yīng)用,因?yàn)闉g覽器跟很多未知服務(wù)端打交道竟块,無(wú)法把每個(gè)服務(wù)端的證書(shū)都保存到本地壶运,但CS架構(gòu)的手機(jī)APP事先已經(jīng)知道要進(jìn)行通信的服務(wù)端,可以直接在客戶(hù)端保存這個(gè)服務(wù)端的證書(shū)用于校驗(yàn)浪秘。
- 為什么直接對(duì)比就能保證證書(shū)沒(méi)問(wèn)題蒋情?
如果中間人從客戶(hù)端取出證書(shū),再偽裝成服務(wù)端跟其他客戶(hù)端通信秫逝,它發(fā)送給客戶(hù)端的這個(gè)證書(shū)不就能通過(guò)驗(yàn)證嗎恕出?
確實(shí)可以通過(guò)驗(yàn)證,但后續(xù)的流程走不下去违帆,因?yàn)橄乱徊娇蛻?hù)端會(huì)用證書(shū)里的公鑰加密浙巫,中間人沒(méi)有這個(gè)證書(shū)的私鑰就解不出內(nèi)容,也就截獲不到數(shù)據(jù),這個(gè)證書(shū)的私鑰只有真正的服務(wù)端有的畴,中間人偽造證書(shū)主要偽造的是公鑰渊抄。
如何使用AFNetworking發(fā)送HTTPS請(qǐng)求
建立自己的安全策略(Security Policy)
AFSecurityPolicy分三種驗(yàn)證模式:
- AFSSLPinningModeNone
這個(gè)模式表示不做SSL pinning,只跟瀏覽器一樣在系統(tǒng)的信任機(jī)構(gòu)列表里驗(yàn)證服務(wù)端返回的證書(shū)丧裁。若證書(shū)是信任機(jī)構(gòu)簽發(fā)的就會(huì)通過(guò)护桦,若是自己服務(wù)器生成的證書(shū),這里是不會(huì)通過(guò)的煎娇。
- AFSSLPinningModeCertificate
這個(gè)模式表示用證書(shū)綁定方式驗(yàn)證證書(shū)二庵,需要客戶(hù)端保存有服務(wù)端的證書(shū)拷貝,這里驗(yàn)證分兩步缓呛,第一步驗(yàn)證證書(shū)的域名/有效期等信息催享,第二步是對(duì)比服務(wù)端返回的證書(shū)跟客戶(hù)端返回的是否一致。
這里還沒(méi)弄明白第一步的驗(yàn)證是怎么進(jìn)行的哟绊,代碼上跟去系統(tǒng)信任機(jī)構(gòu)列表里驗(yàn)證一樣調(diào)用了SecTrustEvaluate因妙,只是這里的列表?yè)Q成了客戶(hù)端保存的那些證書(shū)列表。若要驗(yàn)證這個(gè)票髓,是否應(yīng)該把服務(wù)端證書(shū)的頒發(fā)機(jī)構(gòu)根證書(shū)也放到客戶(hù)端里攀涵?
- AFSSLPinningModePublicKey
這個(gè)模式同樣是用證書(shū)綁定方式驗(yàn)證,客戶(hù)端要有服務(wù)端的證書(shū)拷貝洽沟,只是驗(yàn)證時(shí)只驗(yàn)證證書(shū)里的公鑰以故,不驗(yàn)證證書(shū)的有效期等信息。只要公鑰是正確的玲躯,就能保證通信不會(huì)被竊聽(tīng)据德,因?yàn)橹虚g人沒(méi)有私鑰,無(wú)法解開(kāi)通過(guò)公鑰加密的數(shù)據(jù)跷车。
整個(gè)AFSecurityPolicy就是實(shí)現(xiàn)這這幾種驗(yàn)證方式棘利,剩下的就是實(shí)現(xiàn)細(xì)節(jié)了,詳見(jiàn)源碼朽缴。
示例代碼
- (void)testClientCertificate {
NSString *url = @"https://218.244.131.231/ManicureShop/api/order/pay/%@";
NSDictionary *dic = @{@"request" : @{
@"orderNo" : @"1409282102222110030643",
@"type" : @(2)
}
};
NSData *postData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
//stringWithFormat 自定義文字混淆函數(shù)
NSString *sign = [self signWithSignKey:@"test" params:dic];
NSMutableData *body = [postData mutableCopy];
NSLog(@"%@", [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding]);
url = [NSString stringWithFormat:url, sign];
//設(shè)置可以解析的文本
//code =1016錯(cuò)誤因?yàn)檫@里
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithArray:@[@"application/json", @"text/plain",@"text/html"]];
//自定義安全策略
manager.securityPolicy = [self customSecurityPolicy];
[manager POST:url parameters:dic success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
}
//某種和服務(wù)器約定的混淆方式 默認(rèn)使用不混淆
-(id) signWithSingleKey:(NSString *)inString params: (NSDictionary *)inDictionnary {
return inString;
}
//AFNetworking的自定義安全措施
-(AFSecurityPolicy *) customSecurityPolicy {
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"工程根目錄中證書(shū)的名字" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
//初始化時(shí)使用證書(shū)綁定加密 也可以使用公鑰綁定加密 可選有3種模式
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
//允許使用非CA簽名的證書(shū)
//這里有個(gè)問(wèn)題善玫,如果使用的是IP測(cè)試模式 不通過(guò)DNS 需要去AFNet的安全.m文件里注銷(xiāo)掉驗(yàn)證域名的代碼 code=1012因?yàn)檫@里
[securityPolicy setAllowInvalidCertificates:YES];
[securityPolicy setPinnedCertificates:@[certData]];
return securityPolicy;
}
注銷(xiāo)域名驗(yàn)證
前面說(shuō)過(guò),驗(yàn)證站點(diǎn)證書(shū)密强,是通過(guò)域名的茅郎,如果服務(wù)器端站點(diǎn)沒(méi)有綁定域名(萬(wàn)惡的備案),僅靠IP地址上面的方法是絕對(duì)不行的或渤。
需要修改AFNetworking2的源代碼系冗!打開(kāi)AFSecurityPolicy.m文件,找到方法:
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain
將下面這部分注釋掉
// SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
//
// if (!AFServerTrustIsValid(serverTrust)) {
// return NO;
// }
//
// if (!self.validatesCertificateChain) {
// return YES;
// }
這樣薪鹦,AFSecurityPolicy就只會(huì)比對(duì)服務(wù)器證書(shū)和內(nèi)嵌證書(shū)是否一致掌敬,不會(huì)再驗(yàn)證證書(shū)是否和站點(diǎn)域名一致了惯豆。