一、引言
本篇博客主要討論如何在客戶端與服務端之間進行HTTPS網絡傳輸,為了深入理解網絡傳輸的基礎原理,更加靈活的校驗證書,博客的前半部分也將介紹一些HTTPS網絡傳輸原理。當然,文章中有不正和疏漏之處,還望朋友不吝指正,感謝!
二、HTTP與HTTPS
我們都知道,HTTP是一種常用的網絡傳輸協議,它是基于TCP的一種應用層協議,應用層是什么樣的一個概念,通過下面這張示意圖可以很好的理解:
HTTP協議的網絡傳輸十分常見,例如網易的主頁http://www.163.com/。HTTP類型的網絡傳輸使用十分方便,但是其在安全性上卻有很大問題,列舉如下:
1.HTTP協議在傳輸數據時是明文的,任何人通過一個簡單的抓包工具,就可以截獲到所有傳輸數據。
2.HTTP協議在傳輸數據時無法保證數據的完整,在截獲到明文數據后,很容易就可以將其篡改,這也是一些網頁總是被植入惡意廣告的原因。
3.HTTP協議在傳輸數據時無法保證真實性,這也是最恐怖的一點。誤入了域名欺騙的釣魚網站,極容易對用戶帶來財產損失。
基于上面3點安全性的考慮,一種更加安全的網絡傳輸協議勢必要推行,那就是HTTPS。
要理解HTTPS協議,首先需要明白什么是SSL/TLS。SSL全稱“Secure Sockets Layer”,意思為安全套接層。其實由網景公司為了解決HTTP傳輸協議在安全方面的缺陷而設計的。后來被標準化,更名為TLS,全稱“Transport Layer Security”,意思為傳輸層安全協議。
那么現在就好理解了,其實HTTPS就是將HTTP協議與TLS協議組合起來,在不改變HTTP協議原設計的基礎上,為其添加安全性校驗并對傳輸的數據進行加密。那么TLS究竟在網絡傳輸的那一層進行了處理了,下圖可以很好的表示:
三,https工作流程
1.Client發起一個HTTPS(比如https://juejin.im/user/5a9a9cdcf265da238b7d771c)的請求,根據RFC2818的規定,Client知道需要連接Server的443(默認)端口。
2.Server把事先配置好的公鑰證書(public key certificate)返回給客戶端。
3.Client驗證公鑰證書:比如是否在有效期內,證書的用途是不是匹配Client請求的站點,是不是在CRL吊銷列表里面,它的上一級證書是否有效,這是一個遞歸的過程,直到驗證到根證書(操作系統內置的Root證書或者Client內置的Root證書)。如果驗證通過則繼續,不通過則顯示警告信息。
4.Client使用偽隨機數生成器生成加密所使用的對稱密鑰,然后用證書的公鑰加密這個對稱密鑰,發給Server。
5.Server使用自己的私鑰(private key)解密這個消息,得到對稱密鑰。至此,Client和Server雙方都持有了相同的對稱密鑰。
6.Server使用對稱密鑰加密“明文內容A”,發送給Client。
7.Client使用對稱密鑰解密響應的密文,得到“明文內容A”。
8.Client再次發起HTTPS的請求,使用對稱密鑰加密請求的“明文內容B”,然后Server使用對稱密鑰解密密文,得到“明文內容B”。
四,HTTP 與 HTTPS 的區別
- HTTP 是明文傳輸協議,HTTPS 協議是由 SSL+HTTP 協議構建的可進行加密傳輸、身份認證的網絡協議,比 HTTP 協議安全。
關于安全性,用最簡單的比喻形容兩者的關系就是卡車運貨,HTTP下的運貨車是敞篷的,貨物都是暴露的。而https則是封閉集裝箱車,安全性自然提升不少。
- HTTPS比HTTP更加安全,對搜索引擎更友好,利于SEO,谷歌、百度優先索引HTTPS網頁;
- HTTPS需要用到SSL證書,而HTTP不用;
- HTTPS標準端口443,HTTP標準端口80;
- HTTPS基于傳輸層,HTTP基于應用層;
- HTTPS在瀏覽器顯示綠色安全鎖,HTTP沒有顯示;
五、CA證書的作用,形象解釋
通過前面所介紹,我們知道HTTPS主要是為了解決3個問題:數據加密、數據完整、數據真實。那么下一步就是如何解決這些問題,數據加密在發送數據前依賴SSL層對數據進行加密,數據完整與真實性則要靠另一種關鍵技術:數字證書。
通過一個小例子可以很容易的理解證書的作用,這個例子的來源是<編程隨想>的作者,我這里暫且借用一下:A公司的a到B公司辦事,為了證明a確實是A公司的職員而不是商業間諜,A公司會為a提供一個帶有公章的證明,當B公司看到這個證明時,就可以信任辦事員a。對比網絡傳輸,這個證明就是證書,證書可以保證這個網站的真實性。我們繼續往后分析,當B公司與越來越多的公司進行商業合作時,就又有新的問題出現了,比如C公司的c來B公司辦事,就需要拿C公司帶公章的證明,D公司的d來B公司辦事就需要拿D公司帶公章的證明...這樣一來,B公司要存放好多公司的公章和證明的模板,才能夠完成校驗。這樣未免也太麻煩了,對應到網絡傳輸中,客戶端就是B公司,各個網站都有自己的證書文件,這樣客戶端需要安裝信任大量的證書,為了解決這樣的問題,就有了第三方CA機構。第三方CA機構是由大家公認信任的機構,例如R公司為第三方信任機構,其業務是為其他公司提供公章證明,這樣一來,B公司只要保有這個R公司的公章證明副本,其他A,C,D公司的辦事員也只需要從R公司申請到一個公章證明就可以到B公司來交流業務了。
CA的全稱是“Certificate Authority”,意為證書授權中心。大部分CA機構頒發的證書都是需要付費的,CA機構頒發的證書一般都是根證書,根證書也比較容易理解,首先證書是有鏈式信任關系的,例如Y證書是由CA機構頒發的根證書,由這個Y證書還可以創建出許多子證書,子證書可以繼續創建子證書,只要根證書是受信任的,其下所有的子證書都是受信任的,如下圖:
我們可以打開開源中國博客的主頁:https://www.oschina.net/blog。在Chrome瀏覽器地址欄左邊可以查看證書信息,如下:
點擊證書信息,可以看到完整的證書鏈,如下圖:
從圖中可以看到,根證書是由CA機構VerSign公司頒發的。此處還可以看到當前證書是否有效以及過期時間,如果證書無效則說明此網頁信息有可能被篡改過,用戶在訪問時就要小心了。
除了CA機構可以簽發證書外,個人其實也是可以創建證書的,當然個人創建的證書也是不被信任的,我們姑且把這類證書叫做自簽名證書,如果用自簽名證書搭建了HTTPS的服務,則客戶端需要安裝對應的證書信任,才可以進行此服務的訪問。后面我們會進一步討論自簽名證書的使用。
六、搭建一個本地的HTTPS服務
使用Node.js可以快速的搭建前端服務,我們這里使借助Express框架來搭建本地的HTTPS服務,用于測試我們后邊將要進行HTTPS通訊。Express搭建搭建項目模板的過程在以前的一篇博客中有詳細的介紹,這里就不再重復了,地址如下:
使用Express搭建前端項目:https://my.oschina.net/u/2340880/blog/794928。
根據前面所述,搭建HTTPS服務需要有證書憑證,兩種證書我們可以選擇,一種是CA機構簽發的證書,還有一種是我們自己制作的自簽名證書,在Mac電腦上打開鑰匙串訪問應用,打開其中的證書助理,如下圖所示:
選擇其中的為您自己創建證書選項,如下圖:
在之后的界面中,輸入證書的名稱,選擇證書類型,如下圖所示:
上面,我把證書的名字創建成了琿少,身份類型選擇的是自簽名的根證書,證書類型選擇SSL服務器,之后點擊創建即可完成證書的創建。
創建完成后,在鑰匙串訪問的登錄證書中,可以看到已經有了琿少這個自簽名的證書,如下圖:
在證書上點擊右鍵,選擇導出選項,名字我將其取名為huishao,文件類型要選擇.p12,如下圖所示:
點擊存儲后,需要設置一個訪問密碼,這個密碼將來將用于從.p12文件中獲取證書和密鑰,如下圖所示:
之后,系統有可能會讓你再次輸入一個密碼,將入下圖所示,注意,這里需要輸入的是系統的登錄密碼:
完成上面操作后,我們已經將一個.p12文件導出到了桌面。那么這個.p12文件到底是個什么東西呢,它和證書之間又有什么關系呢,其實.p12文件一個復合文件,其中包裝了私鑰與證書信息,使用OpenSSL工具可以將其中的信息進行提取,搭建一個HTTPS的服務器需要兩個文件,分別問證書文件和私鑰文件,下面我們來從.p12文件中提取這些需要的文件。
打開終端,cd到huishao.p12文件所在的目錄下,使用如下命令可以將.p12文件中的私鑰分解出來:
openssl pkcs12 -in huishao.p12 -nocerts -out privateKey.pem -nodes
之間會要求輸入導出.p12文件時所設置的密碼。
使用如下命令將.p12文件中的證書分解出來:
openssl pkcs12 -in huishao.p12 -nokeys -out cert.pem -nodes
之間也會要求輸入導出.p12文件時所設置的密碼。完成上面兩部操作后,可以看到當前文件夾下多了兩個文件,分別為cert.pem與privateKey.pem,他們分別是證書文件與密鑰文件,將他們拷貝到Express項目的bin文件夾下,使得Express項目的結構看起來如下圖所示:
下面我們來配置Express項目。
在生成好的Express項目中的www文件的末尾添加如下代碼:
/*
HTTPS
*/
var fs = require('fs');
var https = require('https');
/*
密鑰文件
*/
var privatekey = fs.readFileSync('./privateKey.pem', 'utf8');
/*
證書文件
*/
var certificate = fs.readFileSync('./cert.pem', 'utf8');
var options={key:privatekey, cert:certificate};
var serverHttps = https.createServer(options, app);
/*
綁定端口
*/
serverHttps.listen(8080,function () {
console.log('Https server listening on port ' + 8080);
});
用終端在bin文件夾下運行 node www,效果如下:
在瀏覽器打開:https://localhost:8080/users,如果服務器搭建成功,Chrome中會出現如下效果:
點擊高級,點擊其中的繼續訪問,可以正常獲取到服務器返回的數據。到此,我們的HTTPS服務就搭建成功了。
六、iOS開發中通過配置info.plist文件來允許HTTP協議類型的通訊
前面扯了太多,終于提到重點部分了。Apple在iOS9中就已經漏出一些強制HTTPS通訊的端倪,只是給了開發者一些過渡,在iOS10及以后的審核機制中,Apple對于強制HTTPS的推動將會越來越強,如何讓自己的應用程序盡快的適配HTTPS相關的標準,是iOS開發者必須面對的任務。
通過前面的分析我們了解,CA機構簽發的證書是被默認信任的,這就是說,如果你的公司比較有錢,愿意花錢從CA機構申請一個付費的證書,那么很幸運,你的iOS工程是不需要做任何修改的,這些CA機構簽發的證書是默認受信任的,因此你可以直接在程序中進行HTTPS類型的請求,所需要修改的只是將請求url改成https開頭。但是另一種情況,無論出于什么原因,你的后臺服務用的是自簽名的證書,就想我們上面搭建的HTTPS服務一樣,如果在不做任何處理的情況下在項目中訪問這樣的服務,就會出現問題了,原因是我們自己創建的自簽名證書是不受信任的,系統默認拒絕了請求,示例如下:
-(void)normalHttps{
NSURLRequest * req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://localhost:8080/users"]];
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
[[session dataTaskWithRequest:req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@,%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],error);
}] resume];
}
運行工程后可以看到,并沒有獲取到相關數據,Xcode提示為:
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
好了,那么我們先不管HTTPS的問題,如果我們直接對HTTP協議的服務進行請求,會不會有問題呢,將代碼修改如下:
-(void)normalHttps{
NSURLRequest * req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:3000/users"]];
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
[[session dataTaskWithRequest:req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@,%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],error);
}] resume];
}
需要注意:Express在進行項目模板的創建時,會默認幫我們綁定一個3000端口的HTTP服務。
運行工程后,可以發現HTTP協議的請求也無法訪問,報錯如下:
App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
其意思大致是說應用程序傳輸安全要求強制使用HTTPS類型的服務,但是開發者可以通過配置info.plsit文件來回避這一政策。這就是我們這節的重點,通過文件配置的方式來跳過應用安全傳輸協議。
在iOS9之后,開發者可以在Info.plist文件中添加如下鍵:NSAppTransportSecurity。這個鍵用來配置APP傳輸安全的相關策略,是字典類型,其中可以設置的鍵有五個,如下:
NSAllowsArbitraryLoads:布爾值,默認為NO,設置為YES則代表除了NSExceptionDomains中設置的域名外,其他所有請求的協議類型都不受限制,也就是說可以支持HTTP類型的請求,這個鍵的作用域是全局的,App內所有的請求都受影響,但是如果開發者設置為了YES,在提交審核時需要說明原因。
NSAllowsArbitraryLoadsForMedia:布爾值,默認為NO,設置為YES的話,則應用程序內所有的媒體數據的加載將不受協議類型的限制,同樣如果開發者設置為了YES,則在提交審核時需要說明原因。
NSAllowsArbitraryLoadsInWebContent:布爾值,默認為NO。如果設置為YES,則應用程序內所有WebView的請求加載不受協議類型的限制,開發者設置為了YES,則在提交審核時需要說明原因。
NSAllowsLocalNetworking:布爾值,默認為NO,如果設置為YES,則在加載本地資源時不受安全傳輸協議的限制。
NSExceptionDomains:字典,其主要對某些特殊域名做限制。其中結構可以表示如下:
NSAppTransportSecurity : Dictionary {
NSAllowsArbitraryLoads : Boolean
NSAllowsArbitraryLoadsForMedia : Boolean
NSAllowsArbitraryLoadsInWebContent : Boolean
NSAllowsLocalNetworking : Boolean
//對某些域名做特殊限制
NSExceptionDomains : Dictionary {
<domain-name-string> : Dictionary {
NSIncludesSubdomains : Boolean
NSExceptionAllowsInsecureHTTPLoads : Boolean
NSExceptionMinimumTLSVersion : String
NSExceptionRequiresForwardSecrecy : Boolean // Default value is YES
NSRequiresCertificateTransparency : Boolean
}
}
}
NSIncludesSubdomains:布爾值,這個鍵的作用是設置此域名下的所有子域名是否采用和父域名相同的配置。
NSExceptionAllowsInsecureHTTPLoads:布爾值,設置是否允許此域名使用自簽名的證書進行請求,默認為NO,如果設置為YES,則在提交時需要說明原因。
NSExceptionMinimumTLSVersion:設置所使用的TLS版本。
NSExceptionRequiresForwardSecret:設置為NO,則不允許向前加密方式。
NSRequiresCertificateTransparency:如果設置為YES,則服務端的證書要有有效的透明時間戳。
七、iOS中使用自簽名的證書進行HTTPS請求校驗
通過Info.plist文件我們是可以繞過安全傳輸協議的,但是不幸的是,從文檔上看,無論開發者通過哪種方式來繞過安全傳輸協議,Apple都要求開發者在提審時提供合適的理由,這就是說:如果你使用了HTTP協議的請求,沒有充足理由的話,你的App有很大的可能被審核拒絕。因此,更加保險的一種方式是將所有的服務都換成HTTPS協議的,如果有CA證書,當然完事大吉,如果沒有,我們也可以通過驗證自簽名證書的方式來適配HTTPS協議。
在進行HTTPS請求時,服務端會先將證書文件返回給客戶端,如果客戶端的證書信任列表中包含這個證書,則此請求可以正常進行,如果沒有,則請求會被拒絕。因此,在iOS中適配自簽名證書的HTTPS請求實際上就是將這個自簽名的證書安裝進客戶端的信任列表。iOS中需要使用的證書是der格式的,可以使用如下命令將pem格式的證書轉換成der格式的證書:
openssl x509 -inform PEM -in cert.pem -outform DER -out cert.der
將生成的cert文件添加進工程中,修改請求如下:
-(void)normalHttps{
NSURLRequest * req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://localhost:8080/users"]];
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionTask * task = [session dataTaskWithRequest:req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@,%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],error);
}];
[task resume];
}
除此之外,需要實現一個SURLSessionDelegate的協議方法如下:
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler {
NSLog(@"證書認證");
//先判斷證書是否有效
if ([[[challenge protectionSpace] authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust]) {
//證書驗證請求
SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
/**
* 導入多張CA證書(Certification Authority,支持SSL證書以及自簽名的CA)
*/
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"cert" ofType:@"der"];//自簽名證書
NSData* caCert = [NSData dataWithContentsOfFile:cerPath];
//可以添加多張證書
NSArray *caArray = @[caCert];
//驗證規則
NSMutableArray *policies = [NSMutableArray array];
[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
NSMutableArray *pinnedCertificates = [NSMutableArray array];
//進行自簽名證書的添加
for (NSData *certificateData in caArray) {
[pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
}
SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
SecTrustResultType result = -1;
//通過本地導入的證書來驗證服務器的證書是否可信
SecTrustEvaluate(serverTrust, &result);
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
return [[challenge sender] useCredential: credential
forAuthenticationChallenge: challenge];
}
}
如上修改后,再次運行工程,可以看到已經成功請求到了HTTPS自簽名證書服務提供的數據:
介于篇幅過長,關于NSURLAuthenticationChallenge相關類的更多探討和常用網絡庫AFNetworking中HTTPS的適配,下篇博客會繼續介紹。
八,CA證書與自簽名證書的異同
如果你想要構建一個成功的網站,安全是關鍵因素之一,對于需要從訪問者那里收集PIA(personally identifiable information,個人識別信息)的網站而言,尤其如此。
考慮一個需要輸入社會保險號的網站,或更常見的,需要向其添加信用卡信息以完成購買行為的電子商務網站,在這樣的網站上,安全不僅僅是來自那些訪問者的期望,更是成功的關鍵。
如果你正在構建一個電子商務網站,首先就需要一個安全證書以便保證服務器的數據安全,對于證書的選擇,即可以創建自簽名證書,也可以從證書頒發機構(CA)獲得由其簽名的證書,讓我們看看這兩種證書的異同。
CA簽名的證書和自簽名證書的相似性
無論你的證書是由CA簽名的,還是自己簽名的,有一件事是完全相同的:你會得到一個安全的網站。通過HTTPS/SSL連接發送的數據將被加密,第三方無法竊聽。
既然自簽名證書也能做到這一點,那為何要向CA付款呢?
CA告訴你的客戶:此服務器信息已由”信任源點“驗證,最常用的CA是Verisign。CA會驗證你的域名的所有權并頒發證書,這就能保證網站是安全而且合法的。
使用自簽名證書的問題是,幾乎每一個Web瀏覽器都會檢查HTTPS連接是否由可信的CA簽名,如果該連接是自簽名的,則會將其標記為潛在風險并彈出錯誤消息,你的客戶對該站點信任度就會降低。
簡要總結:CA簽名的證書兼具“身份證明”和“加密”雙重功能,而由于自證身份不可信,自簽名證書就只有加密功能,用于無需身份證明的場合。
在何種情況下可以使用自簽名證書?
由于它們提供了相同的保護能力,所以能在任何使用CA簽名證書的場合中使用自簽名證書,但在某些場合特別適用自簽名證書。例如,自簽名證書非常適合測試HTTPS服務器,你不必僅僅為測試網站就要支付CA簽名證書的費用,只需提醒測試人員他們的瀏覽器可能彈出警告信息。
也可以在需要輸入隱私信息的情況下使用自簽名證書,例如:
●用戶名和密碼表單
●收集個人(非財務)信息
當然,只有那些了解并信任你的人才會使用這樣的網站。
所以你看到了,歸根結底就是“信任”二字。當你使用自簽名證書時,你是在對客戶說:“請相信我——我就是我說的我”;當你使用由CA簽名的證書時,你是在說:“請相信我——因為Verisign可以證明我的身份”。
如果你在做電子商務,就需要一個CA簽名證書。
如果你使用自簽名證書只是為了客戶登錄你的網站,那么他們可能會原諒你,但如果要求他們輸入信用卡或Paypal的信息,那么你真的需要一個CA簽名的證書,因為大多數人信任CA簽名的證書,如果沒有它,就不會通過HTTPS服務器做生意。所以如果你想在你的網站上賣東西,那就投資于證書吧,這只是做生意的成本。
有TrustAsia Technologies,Inc 的簽發機構,就是
HTTPS請求
(1)證書轉換
進到證書路徑,執行openssl x509 -in 證書.crt -out 證書.cer -outform der
語句,這樣就可以得到cer類型的證書了。雙擊,導入電腦。
(2)證書放入工程
a.可以直接把轉換好的cer文件拖動到工程中。
b.可以在鑰匙串內,找到你導入的證書,單擊右鍵,導出項目,就可以導出.cer文件的證書了
(3)配置Info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
(6)使用AFNetworking 3.x版本請求HTTPS
a.校驗證書
// 初始化單例類
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.securityPolicy.SSLPinningMode = AFSSLPinningModeCertificate;
// 設置證書模式
NSString * cerPath = [[NSBundle mainBundle] pathForResource:@"xxx" ofType:@"cer"];
NSData * cerData = [NSData dataWithContentsOfFile:cerPath];
manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[[NSSet alloc] initWithObjects:cerData, nil]];
// 客戶端是否信任非法證書
mgr.securityPolicy.allowInvalidCertificates = YES;
// 是否在證書域字段中驗證域名
[mgr.securityPolicy setValidatesDomainName:NO];
b.不校驗證書
// 初始化單例類
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 設置非校驗證書模式
manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
manager.securityPolicy.allowInvalidCertificates = YES;
[manager.securityPolicy setValidatesDomainName:NO];
iOS開發中實現支持HTTPS,有兩種方法:一是后臺那邊都處理好了,移動端直接可以使用HTTPS接口,二是后臺給移動端一個服務器證書cer 文件,這時我們就需要將cer文件導入到我們的工程中,以下是實現方法
1. 雙擊證書,這時證書已經添加到了鑰匙串中
2. 將cer 文件拖入工程中
3. 如果使用的是AFNetwotking 的話,在代碼中添加以下代碼
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
//證書
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
manager.securityPolicy = securityPolicy;
// 2.設置證書模式
NSString * cerPath = [[NSBundle mainBundle] pathForResource:@"tomcat" ofType:@"cer"]; //tomcat是cer文件的名稱
NSData * cerData = [NSData dataWithContentsOfFile:cerPath];
manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[[NSSet alloc] initWithObjects:cerData, nil]];
// 客戶端是否信任非法證書
manager.securityPolicy.allowInvalidCertificates = YES;
// 是否在證書域字段中驗證域名
[manager.securityPolicy setValidatesDomainName:NO];
至此就已經完成支持HTTPS了
在一般的項目中,可以直接判斷如果允許自簽名證書的話,直接完全信任服務器證書,如果不允許自簽名證書的話,直接拿本地的證書和服務器的證書比較
+ (void)setupFreshNetwork:(BOOL)allowInvalidCertificates{
AFHTTPSessionManager *sessionManager =[ [AFHTTPSessionManager alloc] init];
if (!allowInvalidCertificates) {
sessionManager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
sessionManager.securityPolicy.validatesDomainName = YES;
sessionManager.securityPolicy.allowInvalidCertificates = NO;
} else {
//是否允許無效證書(也就是自建的證書),默認為NO 如果是需要驗證自建證書,需要設置為YES
sessionManager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone]; //完全信任服務器證書;
sessionManager.securityPolicy.validatesDomainName = NO;
sessionManager.securityPolicy.allowInvalidCertificates = YES;
}
}
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode {
NSSet <NSData *> *defaultPinnedCertificates = [self certificatesInBundle:[NSBundle mainBundle]];
return [self policyWithPinningMode:pinningMode withPinnedCertificates:defaultPinnedCertificates];
}
這個函數自動在本地的目錄查找.cer 文件