974
阿裏雲
HTTPS業務場景解決方案__最佳實踐_HTTPDNS-阿裏雲
1 背景說明
發送HTTPS請求首先要進行SSL/TLS握手,握手過程大致如下:
- 客戶端發起握手請求,攜帶隨機數、支持算法列表等參數。
- 服務端收到請求,選擇合適的算法,下發公鑰證書和隨機數。
- 客戶端對服務端證書進行校驗,並發送隨機數信息,該信息使用公鑰加密。
- 服務端通過私鑰獲取隨機數信息。
- 雙方根據以上交互的信息生成session ticket,用作該連接後續數據傳輸的加密密鑰。
上述過程中,和HTTPDNS有關的是第3步,客戶端需要驗證服務端下發的證書,驗證過程有以下兩個要點:
- 客戶端用本地保存的根證書解開證書鏈,確認服務端下發的證書是由可信任的機構頒發的。
- 客戶端需要檢查證書的domain域和擴展域,看是否包含本次請求的host。
如果上述兩點都校驗通過,就證明當前的服務端是可信任的,否則就是不可信任,應當中斷當前連接。
當客戶端使用HTTPDNS解析域名時,請求URL中的host會被替換成HTTPDNS解析出來的IP,所以在證書驗證的第2步,會出現domain不匹配的情況,導致SSL/TLS握手不成功。
2 解決方案
針對“domain不匹配”問題,可以采用如下方案解決:hook證書校驗過程中第2步,將IP直接替換成原來的域名,再執行證書驗證。
下麵分別列出Android和iOS平台的示例代碼。
2.1 Android示例
此示例針對HttpURLConnection接口。
try {String url = "https://140.205.160.59/?sprefer=sypc00";HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();connection.setRequestProperty("Host", "m.taobao.com");connection.setHostnameVerifier(new HostnameVerifier() {/** 關於這個接口的說明,官方有文檔描述:* This is an extended verification option that implementers can provide.* It is to be used during a handshake if the URL's hostname does not match the* peer's identification hostname.** 使用HTTPDNS後URL裏設置的hostname不是遠程的主機名(如:m.taobao.com),與證書頒發的域不匹配,* Android HttpsURLConnection提供了回調接口讓用戶來處理這種定製化場景。* 在確認HTTPDNS返回的源站IP與Session攜帶的IP信息一致後,您可以在回調方法中將待驗證域名替換為原來的真實域名進行驗證。**/@Overridepublic boolean verify(String hostname, SSLSession session) {return HttpsURLConnection.getDefaultHostnameVerifier().verify("m.taobao.com", session);return false;}});connection.connect();} catch (Exception e) {e.printStackTrace();} finally {}
2.2 iOS示例
此示例針對NSURLSession/NSURLConnection接口。
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrustforDomain:(NSString *)domain{/** 創建證書校驗策略*/NSMutableArray *policies = [NSMutableArray array];if (domain) {[policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];} else {[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];}/** 綁定校驗策略到服務端的證書上*/SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);/** 評估當前serverTrust是否可信任,* 官方建議在result = kSecTrustResultUnspecified 或 kSecTrustResultProceed* 的情況下serverTrust可以被驗證通過,https://developer.apple.com/library/ios/technotes/tn2232/_index.html* 關於SecTrustResultType的詳細信息請參考SecTrust.h*/SecTrustResultType result;SecTrustEvaluate(serverTrust, &result);return (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);}/** NSURLConnection*/- (void)connection:(NSURLConnection *)connectionwillSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{if (!challenge) {return;}/** URL裏麵的host在使用HTTPDNS的情況下被設置成了IP,此處從HTTP Header中獲取真實域名*/NSString* host = [[self.request allHTTPHeaderFields] objectForKey:@"host"];if (!host) {host = self.request.URL.host;}/** 判斷challenge的身份驗證方法是否是NSURLAuthenticationMethodServerTrust(HTTPS模式下會進行該身份驗證流程),* 在沒有配置身份驗證方法的情況下進行默認的網絡請求流程。*/if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]){if ([self evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:host]) {/** 驗證完以後,需要構造一個NSURLCredential發送給發起方*/NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];} else {/** 驗證失敗,進入默認處理流程*/[[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];}} else {/** 對於其他驗證方法直接進行處理流程*/[[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];}}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////** NSURLSession*/- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)taskdidReceiveChallenge:(NSURLAuthenticationChallenge *)challengecompletionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler{if (!challenge) {return;}NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;NSURLCredential *credential = nil;/** 獲取原始域名信息。*/NSString* host = [[self.request allHTTPHeaderFields] objectForKey:@"host"];if (!host) {host = self.request.URL.host;}if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {if ([self evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:host]) {disposition = NSURLSessionAuthChallengeUseCredential;credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];} else {disposition = NSURLSessionAuthChallengePerformDefaultHandling;}} else {disposition = NSURLSessionAuthChallengePerformDefaultHandling;}// 對於其他的challenges直接使用默認的驗證方案completionHandler(disposition,credential);}
最後更新:2016-11-23 17:16:07
上一篇:
iOS SDK手冊__SDK手冊_HTTPDNS-阿裏雲
下一篇:
如何利用HTTPDNS降低DNS解析開銷__最佳實踐_HTTPDNS-阿裏雲
停止執行計劃周期調度__執行計劃_API參考_E-MapReduce-阿裏雲
購買雲虛擬主機流量__流量購買_購買指導_雲虛機主機-阿裏雲
阿裏雲日後發展的三大關鍵詞:產品、數據、智聯網
枚舉類型__API參考_E-MapReduce-阿裏雲
查詢別名__alias相關_API 列表_OpenAPI 2.0_移動推送-阿裏雲
在哪裏可以查到SLB的權限定義___負載均衡(SLB)授權問題_授權常見問題_訪問控製-阿裏雲
CDN節點默認緩存策略__運維技術分享_技術運維問題_CDN-阿裏雲
使用實例創建自定義鏡像__鏡像_用戶指南_雲服務器 ECS-阿裏雲
UploadServerCertificate__ServerCertificate相關API_API 參考_負載均衡-阿裏雲
Windows平台使用說明__官方遷移工具_常用工具_對象存儲 OSS-阿裏雲
相關內容
常見錯誤說明__附錄_大數據計算服務-阿裏雲
發送短信接口__API使用手冊_短信服務-阿裏雲
接口文檔__Android_安全組件教程_移動安全-阿裏雲
運營商錯誤碼(聯通)__常見問題_短信服務-阿裏雲
設置短信模板__使用手冊_短信服務-阿裏雲
OSS 權限問題及排查__常見錯誤及排除_最佳實踐_對象存儲 OSS-阿裏雲
消息通知__操作指南_批量計算-阿裏雲
設備端快速接入(MQTT)__快速開始_阿裏雲物聯網套件-阿裏雲
查詢API調用流量數據__API管理相關接口_API_API 網關-阿裏雲
使用STS訪問__JavaScript-SDK_SDK 參考_對象存儲 OSS-阿裏雲