https 安全驗證問題

来源:http://www.cnblogs.com/lurenq/archive/2016/12/20/6202182.html
-Advertisement-
Play Games

最近為了滿足蘋果的 https 要求, 經過努力終於寫出了方法 驗證 SSL 證書是否滿足 ATS 要求 nscurl --ats-diagnostics --verbose https://你的功能變數名稱 PASS 符合要求 輸出滿足 ATS 的證書 openssl s_client -connect ...


最近為了滿足蘋果的 https 要求, 經過努力終於寫出了方法

驗證 SSL 證書是否滿足 ATS 要求

nscurl --ats-diagnostics --verbose https://你的功能變數名稱

PASS 符合要求

輸出滿足 ATS 的證書

openssl s_client -connect 你的功能變數名稱:443 </dev/null 2>/dev/null | openssl x509 -outform DER > https.cer

1. 針對 AFNetWorking (2.6.0之前的版本)

AFSecurityPolicy分三種驗證模式:

AFSSLPinningModeNone

這個模式表示不做SSL pinning,
只跟瀏覽器一樣在系統的信任機構列表裡驗證服務端返回的證書。若證書是信任機構簽發的就會通過,若是自己伺服器生成的證書就不會通過。

AFSSLPinningModeCertificate

這個模式表示用證書綁定方式驗證證書,需要客戶端保存有服務端的證書拷貝,這裡驗證分兩步,第一步驗證證書的功能變數名稱有效期等信息,第二步是對比服務端返回的證書跟客戶端返回的是否一致。 

AFSSLPinningModePublicKey

這個模式同樣是用證書綁定方式驗證,客戶端要有服務端的證書拷貝,
只是驗證時只驗證證書里的公鑰,不驗證證書的有效期等信息。只要公鑰是正確的,就能保證通信不會被竊聽,因為中間人沒有私鑰,無法解開通過公鑰加密的數據。

 

// 正對是 app 新人的機構發佈的 SSL 證書

AFSecurityPolicy * securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];

//allowInvalidCertificates 是否允許無效證書(也就是自建的證書),預設為NO //如果是需要驗證自建證書,需要設置為YES

securityPolicy.allowInvalidCertificates = YES;

//validatesDomainName 是否需要驗證功能變數名稱,預設為YES;

//假如證書的功能變數名稱與你請求的功能變數名稱不一致,需把該項設置為NO;如設成NO的話,即伺服器使用其他可信任機構頒發的證書,也可以建立連接,這個非常危險,建議打開。

//置為NO,主要用於這種情況:客戶端請求的是子功能變數名稱,而證書上的是另外一個功能變數名稱。因為SSL證書上的功能變數名稱是獨立的,假如證書上註冊的功能變數名稱是www.google.com,那麼mail.google.com是無法驗證通過的;當然,有錢可以註冊通配符的功能變數名稱*.google.com,但這個還是比較貴的。

//如置為NO,建議自己添加對應功能變數名稱的校驗邏輯。

securityPolicy.validatesDomainName = YES;

//validatesCertificateChain 是否驗證整個證書鏈,預設為YES

//設置為YES,會將伺服器返回的Trust Object上的證書鏈與本地導入的證書進行對比,這就意味著,假如你的證書鏈是這樣的:

//GeoTrust Global CA // Google Internet Authority G2

// *.google.com //那麼,除了導入*.google.com之外,還需要導入證書鏈上所有的CA證書(GeoTrust Global CA, Google Internet Authority G2);

//如是自建證書的時候,可以設置為YES,增強安全性;假如是信任的CA所簽發的證書,則建議關閉該驗證,因為整個證書鏈一一比對是完全沒有必要(請查看源代碼);

securityPolicy.validatesCertificateChain = NO;  // 2.6.0之前不需要, 之後需要

requestOperationManager.securityPolicy = securityPolicy;

// 如實自建的證書

還需要把證書導入本地工程中, 並天添加以下代碼

NSData *cerData = [self getSSLCerByCerName:@"本地SSL證書的名字 "];
[securityPolicy setPinnedCertificates:@[cerData]];

// 獲取 SSL 證書

+ (NSData *)getSSLCerByCerName:(NSString *)cerName {
NSString *cerPath = [[NSBundle mainBundle] pathForResource:cerName
ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
return certData;
}

 

2. 針對 NSURLConnection

驗證證書的API

相關的Api在Security Framework中,驗證流程如下:

1). 第一步,先獲取需要驗證的信任對象(Trust Object)。這個Trust Object在不同的應用場景下獲取的方式都不一樣,對於NSURLConnection來說,是從delegate方法-connection:willSendRequestForAuthenticationChallenge:回調回來的參數challenge中獲取([challenge.protectionSpace serverTrust])。

2). 使用系統預設驗證方式驗證Trust Object。SecTrustEvaluate會根據Trust Object的驗證策略,一級一級往上,驗證證書鏈上每一級數字簽名的有效性(上一部分有講解),從而評估證書的有效性。

3). 如第二步驗證通過了,一般的安全要求下,就可以直接驗證通過,進入到下一步:使用Trust Object生成一份憑證([NSURLCredential credentialForTrust:serverTrust]),傳入challenge的sender中([challenge.sender useCredential:cred forAuthenticationChallenge:challenge])處理,建立連接。

4). 假如有更強的安全要求,可以繼續對Trust Object進行更嚴格的驗證。常用的方式是在本地導入證書,驗證Trust Object與導入的證書是否匹配。更多的方法可以查看Enforcing Stricter Server Trust Evaluation,這一部分在講解AFNetworking源碼中會講解到。

5). 假如驗證失敗,取消此次Challenge-Response Authentication驗證流程,拒絕連接請求。

ps: 假如是自建證書的,則不使用第二步系統預設的驗證方式,因為自建證書的根CA的數字簽名未在操作系統的信任列表中。

iOS授權驗證的API和流程大概瞭解了,下麵,我們看看在NSURLConnection中的代碼實現:

 

// NSURLConnection Https 安全驗證問題
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace{
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
// 針對的是自建證書, 未受安全機構信任
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
static CFArrayRef certs;
if (!certs) {
NSData*certData =[NSData dataWithContentsOfFile:[[NSBundle mainBundle]
pathForResource:@"本地工程中的SSL證書的名字" ofType:@"cer"]];
SecCertificateRef rootcert
=SecCertificateCreateWithData(kCFAllocatorDefault,CFBridgingRetain(certData));
const void *array[1] = { rootcert };
certs = CFArrayCreate(NULL, array, 1, &kCFTypeArrayCallBacks);
CFRelease(rootcert);
}

SecTrustRef trust = [[challenge protectionSpace] serverTrust];
// 針對一個證書對應多個功能變數名稱, 無需驗證功能變數名稱
NSMutableArray *policies = [NSMutableArray array];
// BasicX509 不驗證功能變數名稱是否相同
SecPolicyRef policy = SecPolicyCreateBasicX509();
[policies addObject:(__bridge_transfer id)policy];
SecTrustSetPolicies(trust, (__bridge CFArrayRef)policies);
int err;
SecTrustResultType trustResult = 0;
err = SecTrustSetAnchorCertificates(trust, certs);
if (err == noErr) {
err = SecTrustEvaluate(trust,&trustResult);
}
CFRelease(trust);
// kSecTrustResultUnspecified: 系統隱式地信任這個證書
// kSecTrustResultProceed: 用戶加入自己的信任錨點,顯式地告訴系統這個證書是值得信任的
BOOL trusted = (err == noErr)
&& ((trustResult == kSecTrustResultProceed)
|| (trustResult == kSecTrustResultUnspecified));
if (trusted) {
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]
forAuthenticationChallenge:challenge];
}else{
[challenge.sender cancelAuthenticationChallenge:challenge];
}
}


// SSL 證書是經過信任的機構授權的, 不用再把證書存放在本地
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
//1)獲取trust object
SecTrustRef trust = challenge.protectionSpace.serverTrust;
SecTrustResultType result;

// 針對一個證書對應多個功能變數名稱, 無需驗證功能變數名稱
NSMutableArray *policies = [NSMutableArray array];
// BasicX509 不驗證功能變數名稱是否相同
SecPolicyRef policy = SecPolicyCreateBasicX509();
[policies addObject:(__bridge_transfer id)policy];
SecTrustSetPolicies(trust, (__bridge CFArrayRef)policies);

//2)SecTrustEvaluate對trust進行驗證
OSStatus status = SecTrustEvaluate(trust, &result);
if (status == errSecSuccess &&
(result == kSecTrustResultProceed ||
result == kSecTrustResultUnspecified)) {
//3)驗證成功,生成NSURLCredential憑證cred,告知challenge的sender使用這個憑證來繼續連接
NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
[challenge.sender useCredential:cred forAuthenticationChallenge:challenge];

} else {
//5)驗證失敗,取消這次驗證流程
[challenge.sender cancelAuthenticationChallenge:challenge];
}
}

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • React 是使用ES6 ,支持JSX語法, 開發組件化web或native的工具. 現階段使用Babel工具轉換成ES5 代碼. 組件通過props屬性傳遞不變化的內容,UI通過state屬性變動來產生變化. React 一個界面框架, 數據的管理在js中比較麻煩, 容易混亂 . 有個redux庫 ...
  • 折騰了大半年的項目,用的angular折騰快瘋了。 總算有個小結了。正好閑下來為新的項目做準備,學點新的玩意玩玩,以往ES6都沒用過,感覺被大部隊甩好遠了,抓緊跟上大部隊的腳步... 1.利用let和const引入塊級作用域 通過ES6中定義的let關鍵字可以形成僅作用於該塊作用域的局部變數 與le ...
  • 最近在用 Xamarin 做一個 Android 應用,打開應用時,如果有新消息,需要在應用內的 Toolbar 或者首頁的圖標上顯示數字提示。在這裡和大家分享一下實現方法,如果你有更新好的實現方法,歡迎分享。 類似推特客戶端的新消息提醒 解決思路:把圖標和數字提示文本放在 RelativeLayo ...
  • 今天快要下班了,都準備收拾電腦下班,突然微信推送了個消息:小程式通過微信審核了,按耐不住心中的喜悅,主動加班給大家分享這次通過審核的一些總結。 審核通過後,處於審核通過,待發佈狀態 小程式介紹 我們做的這個小程式是熱點雲筆記,是一個很簡單的記事本,主要是通過微信登錄,讓用戶免輸入賬號雲端同步文本。 ...
  • 這裡主要介紹一下檢查迴圈定義的結構體、聯合體。是對成員中包含自己本身的結構體、聯合體進行檢查。所謂“成員中包含自己本身”,舉例來說,就是指下麵這樣的定義。 這裡所說的“成員中包含自己本身”是指直接包含自己本身,通過指針來應用自己本身是沒有問題的。例如剛纔的例子,如果是下麵這樣的話就沒有問題了。 剛纔 ...
  • 由OpenDigg 出品的安卓開源項目周報第二期來啦。我們的安卓開源周報集合了OpenDigg一周來新收錄的優質的安卓開發方面的開源項目,方便安卓開發人員便捷的找到自己需要的項目工具等。 ...
  • 今天拉同事最新的代碼,編譯時老是報如下錯誤: Error:Could not find com.android.tools.build:gradle:2.2.0.Searched in the following locations: file:/D:/software/android-studio ...
  • 轉載請標明出處:http://www.cnblogs.com/zhaoyanjun/p/6202369.html 本文出自 "【趙彥軍的博客】" 在Android Studio項目裡面有個local.properties文件,這個文件可以放一些系統配置。比如:sdk路徑、ndk路徑。 當然我們也可以 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...