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信息一致後,您可以在回調方法中將待驗證域名替換為原來的真實域名進行驗證。
*
*/
@Override
public 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)serverTrust
forDomain:(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 *)connection
willSendRequestForAuthenticationChallenge:(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 *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(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-阿裏雲