iOS 客戶端 HTTPS 防中間人攻擊實踐
原文鏈接:iOS 客戶端 HTTPS 防中間人攻擊實踐
作者:MrPeak
寫篇文章介紹些以前在 iOS 客戶端實踐 HTTPS 安全的經歷。
不同工程師寫代碼的習慣不一樣,有些喜歡邊寫邊查,即使在接觸陌生的知識域時,也要先寫一些代碼,遇到難題再去 google 或者 stackoverflow 找答案,另一些則習慣在動手之前,先儲備足夠多的理論知識,在建立整體認知之後再定框架填細節。我個人建議初學者採用第一種方式,而對於有一定工作年限且尋求專業度提升的工程師來說,後者是更合理的方式。
關於客戶端如何實踐 HTTPS,所涉及的知識點非常多,如果不預先建立相關知識框架,熟悉背後的理論體系,寫出 bug,給隊友埋坑可以說是個大概率事件。個人建議可以圍繞 PKI 體系和 HTTPS 網路流量分析這兩塊著手,逐步完善知識細節。
HTTPS 防中間人攻擊是 PKI 知識體系的一個應用場景,關鍵在於明白簽名的意義,簽名的目的在於身份認證,背後設計的演算法理論雖然有些複雜,但整個流程卻很直觀清晰。
中間人攻擊場景涉及三個角色,客戶端,伺服器,以及 CA(證書籤發機構)。CA 主要用來解決 Client 和 Server 之間的信任問題,相當於一個背書的角色。CA 通過簽發證書的方式,來確認 Client 和 Server 的身份,具體到 iOS 客戶端,CA 一般向 Server 簽發證書,告知 Client,持有某個證書的 Server,其身份是可以被信任的。那誰來確認 CA 所說的話是可以被信任的呢?操作系統會內置一些知名 CA 的公鑰,這些知名 CA 在簽發證書的時候會通過審核確認,確保 Server 的身份和其所宣稱的一致。
所有圍繞中間人攻擊的場景都是根據 CA 來展開的。
一般場景下,iOS 客戶端的證書校驗邏輯會檢查 CA 是否被信任,可以避免中間人攻擊。只不過在一些特定場景下會讓中間人攻擊有機可乘,比如用戶自己在 iPhone 上添加可被信任的 CA。之前我寫過一篇使用 mitmproxy,實施中間人攻擊知乎 iOS 客戶端的文章,其原理就是利用用戶自己添加 mitimproxy 為可信任 CA,這樣 mitmproxy 可以在截獲 https 流量之後,進行證書校驗的時候,臨時簽發證書,欺騙證書的校驗過程。所以,任何時刻都不要隨意添加第三方 CA 信任,這是客戶端安全的一道大門。
如果不亂添加第三方 CA,不隨意使用網路代理,是否就可以避免中間人攻擊呢?凡事無絕對,以前就出現過不少第三方 CA 爆安全漏洞的例子,讓攻擊者可以簽發出來自知名 CA 的證書,這種例子雖然少,卻不是沒有。
另外,iOS 系統為了加強安全性,降低用戶誤操作所帶來的安全隱患,從 iOS 10.3 開始,將添加證書和信任證書分開處理。即使在用戶添加證書之後,還需要在另外一個位置手動開啟信任,才能讓第三方 CA 獲得簽發證書被信任的能力,具體位置是:Settings > General > About > Certificate Trust Settings。
對於 iOS 開發者來說,防中間人攻擊可以從兩方面著手。
第一是通訊內容本身加密,無論是走 http 還是 https,request 和 response 的內容本身都要先做一次加密,這樣即使 https 的流量被破解,攻擊者還需要再攻破一層加密演算法。我們一般使用 AES 256 對內容做加密,這裡 AES 密鑰的管理也有兩種方式,其一是在客戶端使用固定的密鑰,為了加大破解的難度,我們可以對密鑰本身做多次加密處理,使用時再在內存里解密出來真正的密鑰。其二是每次會話都使用不同的密鑰,原理類似 Forward Secrecy,即使流量被記錄,將來被暴力破解,也能極大的增加攻擊者破解的時間成本。
第二種就是大家所熟知的 ssl pinning。在客戶端進行代碼層面的證書校驗,校驗方式也有兩種,一是證書本身校驗,而是公鑰校驗。這兩種方式對應到 AFNetworking 中的代碼如下:
enum {n AFSSLPinningModeNone,n AFSSLPinningModePublicKey,n AFSSLPinningModeCertificate,n }n
證書校驗是文件級別的校驗,客戶端只信任若干個證書文件,這些證書文件是和客戶端一起打包發布的,這種處理方式要面對的一個問題證書過期問題,為了避免證書過期導致的校驗失敗,客戶端和伺服器之間需要額外存在一個證書更新機制,其實做起來也比較簡單,只需要伺服器下發一個特定的錯誤碼,觸發一個客戶端的新證書下載流程即可。
公鑰校驗模式可以免去上述的麻煩,公鑰模式只校驗證書中所包含的公鑰是否匹配,即使證書過期了,只要伺服器更新證書,保證公鑰不變,依然能完成校驗過程,但這個大前提是,伺服器的公鑰私鑰對不能更換。
以上所述都是 https 安全相關的主要知識點,有時候還會遇到一些特殊場景,所以預先建立完整的知識體系十分重要。
比如,有些客戶端做了 httpdns,http 請求里是 IP 地址而非域名,這樣自然無法通過證書校驗環節中的域名匹配,這種時候,我們需要干預證書校驗的環節,比如 AFNetworking 允許我們設置 validatesDomainName,NSURLSession 也提供如下方法讓我們對證書校驗過程做一些特殊處理:
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandlern{}n
所以,先儲備好相關理論知識,無論在哪個平台,使用什麼第三方庫,就都能清晰的做代碼層面的 https 安全實踐了。
全文完。
閱讀原文推薦閱讀:
※Let's Encrypt 使用教程,免費的SSL證書,讓你的網站擁抱 HTTPS
※理解HTTPS
※為什麼要把網站升級到HTTPS
※浙大博士在阿里:曾想低頭離開,沒想到一干就停不下來……
※酷站推薦 - ssl.do - SSL.DO | SSL證書