寫篇文章介紹些以前在 iOS 客戶端實踐 HTTPS 安全的經(jīng)歷描孟。
不同工程師寫代碼的習(xí)慣不一樣,有些喜歡邊寫邊查砰左,即使在接觸陌生的知識域時匿醒,也要先寫一些代碼,遇到難題再去 google 或者 stackoverflow 找答案缠导,另一些則習(xí)慣在動手之前廉羔,先儲備足夠多的理論知識,在建立整體認(rèn)知之后再定框架填細(xì)節(jié)僻造。我個人建議初學(xué)者采用第一種方式憋他,而對于有一定工作年限且尋求專業(yè)度提升的工程師來說,后者是更合理的方式髓削。
關(guān)于客戶端如何實踐 HTTPS竹挡,所涉及的知識點非常多,如果不預(yù)先建立相關(guān)知識框架立膛,熟悉背后的理論體系揪罕,寫出 bug,給隊友埋坑可以說是個大概率事件。個人建議可以圍繞 PKI 體系和 HTTPS 網(wǎng)絡(luò)流量分析這兩塊著手耸序,逐步完善知識細(xì)節(jié)忍些。
HTTPS 防中間人攻擊是 PKI 知識體系的一個應(yīng)用場景,關(guān)鍵在于明白簽名的意義坎怪,簽名的目的在于身份認(rèn)證罢坝,背后設(shè)計的算法理論雖然有些復(fù)雜,但整個流程卻很直觀清晰搅窿。
中間人攻擊場景涉及三個角色嘁酿,客戶端,服務(wù)器男应,以及 CA(證書簽發(fā)機構(gòu))闹司。CA 主要用來解決 Client 和 Server 之間的信任問題,相當(dāng)于一個背書的角色沐飘。CA 通過簽發(fā)證書的方式游桩,來確認(rèn) Client 和 Server 的身份,具體到 iOS 客戶端耐朴,CA 一般向 Server 簽發(fā)證書借卧,告知 Client,持有某個證書的 Server筛峭,其身份是可以被信任的铐刘。那誰來確認(rèn) CA 所說的話是可以被信任的呢?操作系統(tǒng)會內(nèi)置一些知名 CA 的公鑰影晓,這些知名 CA 在簽發(fā)證書的時候會通過審核確認(rèn)镰吵,確保 Server 的身份和其所宣稱的一致。
所有圍繞中間人攻擊的場景都是根據(jù) CA 來展開的挂签。
一般場景下疤祭,iOS 客戶端的證書校驗邏輯會檢查 CA 是否被信任,可以避免中間人攻擊饵婆。只不過在一些特定場景下會讓中間人攻擊有機可乘画株,比如用戶自己在 iPhone 上添加可被信任的 CA。之前我寫過一篇使用 mitmproxy啦辐,實施中間人攻擊知乎 iOS 客戶端的文章谓传,其原理就是利用用戶自己添加 mitimproxy 為可信任 CA,這樣 mitmproxy 可以在截獲 https 流量之后芹关,進(jìn)行證書校驗的時候续挟,臨時簽發(fā)證書,欺騙證書的校驗過程侥衬。所以诗祸,任何時刻都不要隨意添加第三方 CA 信任跑芳,這是客戶端安全的一道大門。
如果不亂添加第三方 CA直颅,不隨意使用網(wǎng)絡(luò)代理博个,是否就可以避免中間人攻擊呢?凡事無絕對功偿,以前就出現(xiàn)過不少第三方 CA 爆安全漏洞的例子盆佣,讓攻擊者可以簽發(fā)出來自知名 CA 的證書,這種例子雖然少械荷,卻不是沒有共耍。
另外,iOS 系統(tǒng)為了加強安全性吨瞎,降低用戶誤操作所帶來的安全隱患痹兜,從 iOS 10.3 開始,將添加證書和信任證書分開處理颤诀。即使在用戶添加證書之后字旭,還需要在另外一個位置手動開啟信任,才能讓第三方 CA 獲得簽發(fā)證書被信任的能力崖叫,具體位置是:Settings > General > About > Certificate Trust Settings谐算。
對于 iOS 開發(fā)者來說,防中間人攻擊可以從兩方面著手归露。
第一是通訊內(nèi)容本身加密,無論是走 http 還是 https斤儿,request 和 response 的內(nèi)容本身都要先做一次加密剧包,這樣即使 https 的流量被破解,攻擊者還需要再攻破一層加密算法往果。我們一般使用 AES 256 對內(nèi)容做加密疆液,這里 AES 密鑰的管理也有兩種方式,其一是在客戶端使用固定的密鑰陕贮,為了加大破解的難度堕油,我們可以對密鑰本身做多次加密處理,使用時再在內(nèi)存里解密出來真正的密鑰肮之。其二是每次會話都使用不同的密鑰掉缺,原理類似 Forward Secrecy,即使流量被記錄戈擒,將來被暴力破解眶明,也能極大的增加攻擊者破解的時間成本。
第二種就是大家所熟知的 ssl pinning筐高。在客戶端進(jìn)行代碼層面的證書校驗搜囱,校驗方式也有兩種丑瞧,一是證書本身校驗,而是公鑰校驗蜀肘。這兩種方式對應(yīng)到 AFNetworking 中的代碼如下:
enum {
AFSSLPinningModeNone,
AFSSLPinningModePublicKey,
AFSSLPinningModeCertificate,
}
證書校驗是文件級別的校驗绊汹,客戶端只信任若干個證書文件,這些證書文件是和客戶端一起打包發(fā)布的扮宠,這種處理方式要面對的一個問題證書過期問題西乖,為了避免證書過期導(dǎo)致的校驗失敗,客戶端和服務(wù)器之間需要額外存在一個證書更新機制涵卵,其實做起來也比較簡單浴栽,只需要服務(wù)器下發(fā)一個特定的錯誤碼,觸發(fā)一個客戶端的新證書下載流程即可轿偎。
公鑰校驗?zāi)J娇梢悦馊ド鲜龅穆闊┑浼Γ€模式只校驗證書中所包含的公鑰是否匹配,即使證書過期了坏晦,只要服務(wù)器更新證書萝玷,保證公鑰不變,依然能完成校驗過程昆婿,但這個大前提是球碉,服務(wù)器的公鑰私鑰對不能更換。
以上所述都是 https 安全相關(guān)的主要知識點仓蛆,有時候還會遇到一些特殊場景睁冬,所以預(yù)先建立完整的知識體系十分重要。
比如看疙,有些客戶端做了 httpdns豆拨,http 請求里是 IP 地址而非域名,這樣自然無法通過證書校驗環(huán)節(jié)中的域名匹配能庆,這種時候施禾,我們需要干預(yù)證書校驗的環(huán)節(jié),比如 AFNetworking 允許我們設(shè)置 validatesDomainName搁胆,NSURLSession 也提供如下方法讓我們對證書校驗過程做一些特殊處理:
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{}
所以弥搞,先儲備好相關(guān)理論知識,無論在哪個平臺渠旁,使用什么第三方庫攀例,就都能清晰的做代碼層面的 https 安全實踐了。
全文完顾腊。