Charles 抓包失敗案例分析
1.關閉代理!關閉代理!關閉代理!
作為一名程序員,為了順暢的訪問 GitHub 等網站,我們總會用些“輔助工具”。這些工具一般會自動開啟 HTTP/HTTPS 代理從而搶占端口,導致 Charles 代理失敗。
解決這個問題也很簡單,Charles 抓包前,把電腦和手機的輔助工具都關掉,這樣就不會有代理沖突的問題了。我們可以查看電腦的 Wi-Fi 代理界面,開啟 Charles 抓包前要保證下面的選項都沒被勾選就好了。
肯定也有人想過我們本地掛兩個代理,報文先經過工具,然后經過 Charles 抓包,最后傳輸到客戶端。首先這種方案是可行的,但是實際用下來會非常的卡,延遲也很高,所以並不建議這樣使用。
2.確定數據走的 HTTP 協議嗎?
本小節開始前我們先看一下官方是如何定義 Charles 的:
Charles is an HTTP proxy / HTTP monitor / Reverse Proxy that enables a
developer to view all of the HTTP and SSL / HTTPS traffic between
their machine and the Internet.
從介紹中我們可以看出 Charles 是一款專注於分析 HTTP 報文的網絡工具,所以說對於其它協議支持是非常有限的。比如說現在的 IM 或音視頻應用,出於性能和安全上的考慮,基本都是自己基於某一傳輸層協議自己封裝的,這些數據 Charles 肯定是抓不到的。
通過閱讀 Charles 的官方文檔和自己的測試,Charles 支持以下協議:
- HTTP/1.1
- HTTPS
- HTTP/2
- ws(WebSocket)
- wss(WebSocket Secure,TLS 加密的 WebSocket)
- SOCKS
⚠️ 注:Charles 不支持 HTTP/3,但是大部分開啟 HTTP/3 的網站都做了降級處理。例如用 Chrome 正常訪問
Google 時,走的協議是 HTTP/3,連接 Charles 代理后,協議會降級到 HTTP/2
上面列出的幾個協議,其實已經覆蓋日常業務開發 90% 的應用場景了,若想抓取其他協議的報文,還是老老實實用 Wireshark 吧。
3.之前開了黑白名單,再次抓包忘記關了
我想日常工作中,你或你的同事肯定遇到過這種場景:
測試報上來一個 BUG,自己連上 Charles 打算分析一下 HTTP
報文想定位一下是前端問題還是后端問題,結果發現請求一直打不通,手忙腳亂半天,才發現自己開了黑白名單,請求都被 Block 掉了
上面案例的黑白名單只是一個統稱,具體到 Charles 里,下面的幾個配置都有可能造成誤解:
- Proxy Settings 的 Options 里過濾了一些網址
- SSL Proxying Settings 沒有匹配所有網址
- Block List/Allow List 做了黑白名單設置
- DNS Spoofing 做了 HOST 的映射
- Map Remote 重定向了請求
- Rewrite 重寫了請求
- …
我寫了幾個高頻的 Charles Tools,這些功能很有可能在你開啟后就忘記關閉了,如果出了問題難道就要一一排查嗎?
其實 Charles 有一個很不起眼的功能,那就是它的 UI 界面右下角會展示 Charles 正在開啟的功能,如果你懷疑你的 Charles 哪里做了接口限制,你就掃一眼右下角開啟的功能,然后依次檢查就可。
4.Android 版本越高,HTTPS 報文越難抓
用戶自己安裝的 CA 證書沒有 ROOT 權限。
我們先看一張圖,這個是 Android 的證書信任頁面:
從上圖可以看出,Android 系統把證書信任分為兩大塊:
- 系統 CA 證書:基本擁有所有權限
- 用戶 CA 證書:用戶自行安裝,權限很低
我們自己安裝的 Charles 證書都屬於用戶 CA 證書。除了證書的權限問題,Android 的不同版本對權限的處理規則也不一樣:
✅:Android 7.0 以下:信任用戶 CA 證書,可以簡單的理解為我們安裝的證書直接獲得 ROOT 權限
✅:Android 7.0 以上, targetSdkVersion < 24:信任用戶 CA 證書
❌:Android 7.0 以上, targetSdkVersion >= 24:不信任用戶 CA 證書
通過以上的分析,我們可以得出幾個讓 Android 信任 Charles 證書的方案:
- ROOT
直接 ROOT Android 手機,把 Charles 證書放到系統證書里,實現證書洗白 - 准備一個低於 Android 7.0 的手機
Android 7.0 是 2016 年的系統,按照 Android 手機兩年一換代一年一更新的速度算,這種手機很難找到了 - 准備一個 targetSdkVersion < 24 的 APP 安裝包
國內各大應用市場 2019 年統一要求 APP API 版本必須大於 28,這種安裝包很難找到了,而且互聯網產品迭代這么快,不一定能保證安裝包可用 - 騷操作
正常大道走不通,Android 小道還是有很多的。社區上有各種輪子可以繞開限制,但和 Charles 關系不大,我就不展開說了。喜歡折騰的同學可以研究一下。
上面的幾個方案都是針對其它 APP 的,如果你想抓包的應用是自己公司的,那就很簡單了。
Android 有個 res/xml/network_security_config.xml 文件,意如其名,這個配置文件是專門控制網絡安全的。
比如下面的配置,release 包只信任 system 級別的證書,debug 包同時信任 system 和 user 級別的證書,這樣我們在 debug 環境下就可以開心的用 Charles 抓包了。當然安全配置肯定不止這一點內容,感興趣的同學可以去 Android 開發者官網學習了解。
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true"> <trust-anchors> <certificates overridePins="true" src="system" /> </trust-anchors> </base-config> <debug-overrides> <trust-anchors> <certificates overridePins="true" src="system" /> <certificates overridePins="true" src="user" /> </trust-anchors> </debug-overrides> </network-security-config>
5.證書固定(Certificate Pinning)
證書固定(Certificate Pinning) 是指客戶端內置了服務端真正的公鑰證書。
在 HTTPS 請求時,服務端發給客戶端的公鑰證書必須和客戶端內置的公鑰證書一致才能請求成功。一般對安全比較重視的公司會采取這種操作。
在這種情況下,利用 Charles 抓包時,Charles 的公鑰證書和客戶端的公鑰證書不一樣,偽造的請求就會被駁回,我們就抓包失敗了。那么這種情況怎么解決?
和前面介紹的一樣,路其實還是有兩條:
- 一條是 Hack 之路,刷機 ROOT,借助工具移除 APP 中固定的公鑰證書;
- 另一條是正路,你擁有這個 APP 的開發權限,那么一般你也就擁有了公鑰證書和隨之配套的私鑰,我們可以把證書和私鑰導入到 Charles
中,解決證書固定引起的困擾。
Charles 導入公鑰證書和私鑰比較簡單,點擊 Charles -> Proxy -> SSL Proxying Setting -> Root Certificate,然后導入 .pem 或 p12 文件即可。
⚠️ 注:.p12 是一種文件格式,同時包含證書和密鑰
6.證書雙向驗證
在絕大部分的情況下,TLS 都是客戶端認證服務端的真實性的,但是在一些非常注重安全的場景下(例如匿名社交),部分 APP 會開啟 TLS 的雙向驗證,也就是說服務端也要驗證客戶端的真實性。
在這種情況,客戶端必然內置了一套公鑰證書和私鑰。相對於服務端,APP 有很大的砸殼風險,所以公鑰證書和私鑰一般都是極其隱蔽的,比如說寫到 .so 里,隱藏在一個混淆的媽都不認識的隨機數算法函數里,從而增大破譯難度。
我不是安全專家對這個研究的不深,平常工作也沒遇到這么刁難的問題。從功能面板看,Charles 應該也支持這種極限場景的抓包,但是個人沒有具體實踐過,大家可以嘗試一下。
總結
Charles 抓包是一個很常見的職業技能,如果深入研究,你會發現它涉及到網絡連接的五元組、報文轉發的代理服務、密碼學里的 MITM 和公鑰證書知識。綜合來看,只有掌握這些較為底層的基礎知識,面對工作中各種奇奇怪怪得問題時,才能游刃有余的應對。