https筆記

HTTPS就是將HTTP協議數據包放到SSL/TSL層加密后,在TCP/IP層組成IP數據報去傳輸,以此保證傳輸數據的安全。
證書分為兩種,一種是花錢向CA(證書認證的機構)購買的證書,服務端如果使用的是這類證書的話,那一般客戶端不需要做什么,用HTTPS進行請求就行了,蘋果內置了那些受信任的根證書的。另一種是自己制作的證書,使用這類證書的話是不受信任的(當然也不用花錢買),因此需要我們在代碼中將該證書設置為信任證書。
對于一般的小型網站尤其是博客,可以使用自簽名證書來構建安全網絡,所謂自簽名證書,就是自己扮演 CA 機構,自己給自己的服務器頒發證書。

SSL協議的握手過程:(參考

bg2014092004.png

SSL/TSl握手階段的詳細過程

  • 首先,客戶端(通常是瀏覽器)先向服務器發出加密通信的請求,這被叫做ClientHello請求。
    在這一步,客戶端主要向服務器提供以下信息。
    (1) 支持的協議版本,比如TLS 1.0版。
    (2) 一個客戶端生成的隨機數,稍后用于生成"對話密鑰"。
    (3) 支持的加密方法,比如RSA公鑰加密。
    (4) 支持的壓縮方法。
  • 服務器收到客戶端請求后,向客戶端發出回應,這叫做SeverHello。服務器的回應包含以下內容。
    (1) 確認使用的加密通信協議版本,比如TLS 1.0版本。如果瀏覽器與服務器支持的版本不一致,服務器關閉加密通信。
    (2) 一個服務器生成的隨機數,稍后用于生成"對話密鑰"。
    (3) 確認使用的加密方法,比如RSA公鑰加密。
    (4) 服務器證書。
  • 客戶端收到服務器回應以后,首先驗證服務器證書。如果證書不是可信機構頒布、或者證書中的域名與實際域名不一致、或者證書已經過期,就會向訪問者顯示一個警告,由其選擇是否還要繼續通信。
    如果證書沒有問題,客戶端就會從證書中取出服務器的公鑰。然后,向服務器發送下面三項信息:
    (1) 一個隨機數。該隨機數用服務器公鑰加密,防止被竊聽。
    (2) 編碼改變通知,表示隨后的信息都將用雙方商定的加密方法和密鑰發送。
    (3) 客戶端握手結束通知,表示客戶端的握手階段已經結束。這一項同時也是前面發送的所有內容的hash值,用來供服務器校驗。
    上面第一項的隨機數,是整個握手階段出現的第三個隨機數,又稱"pre-master key"。有了它以后,客戶端和服務器就同時有了三個隨機數,接著雙方就用事先商定的加密方法,各自生成本次會話所用的同一把"會話密鑰"。
  • 服務器收到客戶端的第三個隨機數pre-master key之后,計算生成本次會話所用的"會話密鑰"。然后,向客戶端最后發送下面信息。
    (1)編碼改變通知,表示隨后的信息都將用雙方商定的加密方法和密鑰發送。
    (2)服務器握手結束通知,表示服務器的握手階段已經結束。這一項同時也是前面發送的所有內容的hash值,用來供客戶端校驗。
    至此,整個握手階段全部結束。接下來,客戶端與服務器進入加密通信,就完全是使用普通的HTTP協議,只不過用"會話密鑰"加密內容。

證書

證書的申請過程
  • 證書申請者向頒發證書的可信第三方CA提交申請證書相關信息,包括:申請者域名、申請者生成的公鑰(私鑰自己保存)及證書請求文件.cer等
  • CA通過線上、線下等多種手段驗證證書申請者提供的信息合法和真實性。
  • 當證書申請者提供的信息審核通過后,CA向證書申請者頒發證書,證書內容包括明文信息和簽名信息。其中明文信息包括證書頒發機構、證書有效期、域名、申請者相關信息及申請者公鑰等,簽名信息是使用CA私鑰進行加密的明文信息。當證書申請者獲取到證書后,可以通過安裝的CA證書中的公鑰對簽名信息進行解密并與明文信息進行對比來驗證簽名的完整性。
證書的驗證過程

TSL/SSL的握手過程里client會拿到server返回的證書并且驗證證書本身的合法性(驗證簽名完整性,驗證證書有效期等)

  • 驗證證書頒發者的合法性(查找頒發者的證書并檢查其合法性,這個過程是遞歸的)
  • 證書驗證的遞歸過程最終會成功終止,而成功終止的條件是:證書驗證過程中遇到了錨點證書,錨點證書通常指:嵌入到操作系統中的根證書(權威證書頒發機構頒發的自簽名證書)。
證書驗證失敗的原因
  • 無法找到證書的頒發者
  • 證書過期
  • 驗證過程中遇到了自簽名證書,但該證書不是錨點證書。
  • 無法找到錨點證書(即在證書鏈的頂端沒有找到合法的根證書)
  • 訪問的server的dns地址和證書中的地址不同
iOS實現支持HTTPS

在OC中當使用NSURLConnectionNSURLSession建立URL并向服務器發送https請求獲取資源時,服務器會使用HTTP狀態碼401進行響應(即訪問拒絕)。此時NSURLConnection或NSURLSession會接收到服務器需要授權的響應,當客戶端授權通過后,才能繼續從服務器獲取數據。如下圖所示:

image.png

非自簽名證書驗證實現

當客戶端發送https請求后,服務器會返回需要授權的相關信息,對于NSURLSession而言,,需要代理對象實現URLSession:task:didReceiveChallenge:completionHandler:方法。

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
    
    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    NSURLCredential *credential = nil;
    
    SecTrustRef trust = challenge.protectionSpace.serverTrust;
    SecTrustResultType result;
    OSStatus status = SecTrustEvaluate(trust, &result);
    if (status == kSecTrustResultUnspecified || status == kSecTrustResultProceed) {
        credential = [NSURLCredential credentialForTrust:trust];
        if (credential) {
             disposition = NSURLSessionAuthChallengeUseCredential;
        }
    }
    completionHandler(disposition, credential);
}
  • NSURLSessionAuthChallengePerformDefaultHandling處理請求,就好像代理沒有提供一個代理方法來處理認證請求
  • NSURLSessionAuthChallengeRejectProtectionSpace拒接認證請求。基于服務器響應的認證類型,URL加載類可能會多次調用代理方法。
SecTrustRef

表示需要驗證的信任對象(Trust Object),在此指的是challenge.protectionSpace.serverTrust。包含待驗證的證書和支持的驗證方法等。

SecTrustResultType

表示驗證結果。其中 kSecTrustResultProceed表示serverTrust驗證成功,且該驗證得到了用戶認可(例如在彈出的是否信任的alert框中選擇always trust)。 kSecTrustResultUnspecified表示 serverTrust驗證成功,此證書也被暗中信任了,但是用戶并沒有顯示地決定信任該證書。 兩者取其一就可以認為對serverTrust驗證成功。

SecTrustEvaluate

函數內部遞歸地從葉節點證書到根證書驗證。使用系統默認的驗證方式驗證Trust Object,根據上述證書鏈的驗證可知,系統會根據Trust Object的驗證策略,一級一級往上,驗證證書鏈上每一級證書有效性。

對于非自簽名的證書,即使服務器返回的證書是信任的CA頒發的,假如有更強的安全要求,可以繼續對Trust Object進行更嚴格的驗證。常用的方式是在本地導入證書,并將導入的證書設置成需要參與驗證的錨點證書,再調用SecTrustEvaluate通過本地導入的證書來驗證服務器證書是否是可信的。如果服務器證書是這個錨點證書對應CA或者子CA頒發的,或服務器證書本身就是這個錨點證書,則證書信任通過。如下代碼:

NSString *cerPath = ...;//證書在本次的路徑
NSData *cerData = [NSData dataWithContentsOfFile:cerPath];
SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)cerPath);
self.trustedCertificates = @[CFBridgingRelease(certificate)];

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    NSURLCredential *credential = nil;
    SecTrustRef trust = challenge.protectionSpace.serverTrust;
    SecTrustResultType result;
    
    //將之前導入的證書設置成下面驗證的Trust Object的錨點證書
    SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)self.trustedCertificates);
    //通過本地導入的證書來驗證服務器返回的證書是否可信
    OSStatus status = SecTrustEvaluate(trust, &result);
    if (status == kSecTrustResultUnspecified || status == kSecTrustResultProceed) {
        credential = [NSURLCredential credentialForTrust:trust];
        if (credential) {
            disposition = NSURLSessionAuthChallengeUseCredential;
        }
    }
    
    completionHandler(disposition, credential);
}

自簽名證書

對于自簽名證書,這樣Trust Object中的服務器證書是不可信任的CA頒發的,直接使用SecTrustEvaluate驗證是不會成功的。
可以采取下述簡單代碼繞過HTTPS的驗證:

[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
 [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
綜上對非自建和自建證書驗證過程的分析,可以總結如下:
  • 獲取需要驗證的信任對象(Trust Object)。對于NSURLSession來說,
    是從delegate方法URLSession:task:didReceiveChallenge:completionHandler:回調回來的參數challenge中獲取(challenge.protectionSpace.serverTrust) 。
    使用系統默認驗證方式驗證Trust Object。
  • SecTrustEvaluate會根據Trust Object的驗證策略,一級一級往上,驗證證書鏈上每一級數字簽名的有效性,從而評估證書的有效性。
  • 如第二步驗證通過了,一般的安全要求下,就可以直接驗證通過,進入到下一步:使用Trust Object生成一份憑證([NSURLCredential credentialForTrust:serverTrust]),傳入block中 completionHandler(disposition, credential)處理,建立連接。
  • 假如有更強的安全要求,可以繼續對Trust Object進行更嚴格的驗證。常用的方式是在本地導入證書,驗證Trust Object與導入的證書是否匹配。
  • 假如驗證失敗,取消此次Challenge-Response Authentication驗證流程,拒絕連接請求。
  • 假如是自建證書的,則不使用第二步系統默認的驗證方式,因為自建證書的根CA的數字簽名未在操作系統的信任列表中。

在AFNetwoking的AFURLSessionManager.m這個文件里實現了代理方法URLSession:task:didReceiveChallenge:completionHandler:并且在代理方法里對服務器返回的證書做了驗證。驗證的方法是evaluateServerTrust:forDomain:(NSString *)domain
AFNetwoking提供了一個類AFSecurityPolicy,它有一個屬性:

typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
    AFSSLPinningModeNone,
    AFSSLPinningModePublicKey,
    AFSSLPinningModeCertificate,
};
@property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;

這個枚舉值決定了按哪種方式來驗證服務器返回的證書。默認值是AFSSLPinningModeNone

  • AFSSLPinningModeNone:這會通過SecTrustEvaluate來驗證服務器返回的證書,對于CA認證的證書可以選用這個值;
  • AFSSLPinningModeCertificate:如果使用了CA認證的證書,并且在本地也導入了證書作為錨點證書來驗證服務器返回的證書,可以用這個值。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容