部分APP無法代理抓包的原因及解決方法(flutter 應用抓包)


引言

HTTP應用層的抓包已經成為日常工作測試與調試中的重要一環,最近接觸新項目突然之間發現之前的抓包手段都不好使了,頓時模塊與模塊之間的前端與服務之間的交互都變成了不可見,整個人都好像被蒙住了眼睛。
其實自己也很早就發現平時使用的支付寶等APP使用Fiddler 或 Charles這類代理抓包軟件默認情況下就無法抓取請求的,但使用Wireshark這類網卡抓包軟件可以看到這些APP的流量,而已這些流量也表明這些APP使用的主要應用層協議仍然是HTTP(https),不過我們的代理抓包工具卻失效了。如今終於在實際工作中遇到了,也不得不解決了,畢竟眼前有東西擋住會讓我渾身不適。
 
 

代理抓包原理

為了弄明白為什么Fiddler 或 Charles對這些APP無效,我們有必要先了解代理抓包我原理(當然您不想了解也是完全可以的,直接看后面的 實際操作就可以完成,原理分析什么的可以有興趣隨時回來看)
 
Fiddler 或 Charles 這類使用的代理的抓包軟件與Wireshark是完全不同的(Wireshark 使用的網卡數據復制,只要是經過指定網卡都會被抓取),其只能對使用代理的應用層網絡協議生效,比如常見的HTTP(https),Websocket  。
這里以HTTP為例簡單說明下

 

客戶端需要完成一次HTTP請求,通常需要先找到服務器,客戶端會根據http請求中url的主機名(實際會使用host中的主角名)及其端口與目標主機建立tcp連接,建立連接后會將http報文發送給目標服務器 (更多細節請參考 https://tools.ietf.org/html/rfc7232
 
接下來我來看下HTTP代理是如何運作的,我們啟動Fiddler 或 Charles就是啟動了一個HTTP代理服務器,這類工具會通知操作系統,“現在我在系統上創建了一個HTTP代理,IP為XXXXXX端口為XX。如果您使用的是linux您可以手動通知操作系統(export http_proxy=ip:port export https_proxy=$http_proxy),如果您使用的是手機等移動設備您可以在當前wifi設置處告訴系統你要使用http代理。 現在我們已經告訴系統我們想要使用代理,這個時候運行在系統上的http客戶端再去發送請求的時候,他就不會再去進行DNS解析,去連接目標服務器,而是直接連接系統告訴他代理所在的地址(代理的ip及端口,注意無論是http或https或其他支持代理的協議都會連接同一個端口)。然后代理服務器會與客戶端建立連接,再然后代理服務器根據請求信息再去連接真正的服務器。

 

這里還有個細節正常在沒有代理的情況下客戶端向服務器發送的請求行里只包含部分URI(實際上是沒有方案,主機名及端口的)

 

如上圖如果在沒有代理的情況下,對www.baidu.com/index.html的請求的請求行實際上是GET /index.html HTTP/1.1 其實並不是我們常見的完整uri。因為在原始的HTTP設計中沒有考慮中間服務器(即代理)的情況,客戶端在發送報文前已經知道服務器的地址並與之建立了連接,沒有必要再發送方案,主機名及端口。不過代理出現后這種做法就會有問題了,客戶端連接了代理服務器,而代理服務器卻沒有辦法連接正確的服務器。因此客戶端發送給代理的請求其實稍有不同,客戶端會在請求行里使用完整的uri,這樣代理服務器才能解析真實的服務器的地址。
現在我們的請求實際上都是通過代理服務器(Fiddler 或 Charles)發送出去的,所以代理抓包軟件不僅知道http請求及響應的所有報文,甚至還可以隨時修改請求及響應。
 

部分應用不能抓包的原因

可以看到代理抓包的關鍵就是需要HTTP客戶端按照要求去連接代理服務器,一般情況下我們已經在系統層面上設置了代理,通常http客戶端都是按要求去實現的,在進行http請求前會先檢查系統代理,如果有設置代理,客戶端會直接使用完整uri去連接代理服務器。不同的平台通常會實現自己的的http客戶端的,雖然他們都按照協議要求實現了代理功能,但是並不一定在默認情況下會直接使用系統代理。
在現實中這種況下這種情況還不少,筆者當前項目使用到的Flutter就是這種情況,默認Flutter不會主動使用系統代理,需要單獨設置。(當然個人認為這種策略也是有理由,雖然給測試及調試帶來了不便不過也在一程度上提高了些許數據安全)
正是因為HTTP客戶端沒有使用我們設置的系統代理,他們自然也不會連接Fiddler 或 Charles創建的代理服務器,最終導致我們無法獲取任何請求。
 

解決方案

不過既然我們已經知道了Fiddler 和 Charles不能抓包的具體原因,前面也提到了代理抓包的原理,那我們就總有辦法解決。
前面說到了我們APP使用的HTTP客戶端沒有連接到代理服務器,導致我們的代理抓包軟件無法正常抓包,那我們只要想辦法讓客戶端重新連接到代理服務器就好了(當然這一切都是以不修改客戶端軟件APP為前提的)
方法1:控制DNS解析,通過修改dns的方式讓客戶端以為我們的代理服務器就是目標服務器。
            優勢:操作方便,通過修改設備的hosts可以十分方便的首先
            劣勢:需要為每個需要操作的域名提前添加host
                      在手機等手持設備上難以修改hosts(即對移動APP這類應用很難實現)
 
方法2:在網絡設備上直接做流量轉發,將指定終端設備上發往80及443端口的數據直接轉發到代理服務器的    目標端口上
           優勢:可以針對連接到網絡設備上的終端設備進行分別配置,而手機等終端設備不需要進行任何設備
           劣勢:需要單獨的硬件設備
 
方法3:使用VPN將終端設備的流量轉發到代理服務器
           優勢:使用VPN軟件不用添加其他測試。
           劣勢:終端上的VPN默認會直接對所有流量進行轉發,要進行合理的配置可能需要額外的學習成本
 

實際操作步驟(Android)

筆者這里直接使用上面提到第3種方法(方法1在對於手機APP很難操作,方法2可能需要其他設備所以這里不使用),因為我們的測試對象是手機移動APP,所以我們首先要在手機上安裝一個VPN,這里使用一個十分方便的VPN軟件drony (介紹在這里 https://github.com/SuppSandroB/sandrop/wiki/Drony-FAQ),drony會在你的手機上創建一個VPN,將手機上的所有流量都重定向到drony自身(不是流向vpn服務器) ,這樣drony就可以管理所有手機上的網絡流量,甚至可以對手機上不同APP的流量進行單獨配置。

1:安裝drony  (這里手機使用的Android設備)

     您可以在網絡上搜索drony選擇自己想要的版本進行安裝,或者在這里下載( https://files.cnblogs.com/files/lulianqi/Drony_102.apk),安裝完成后打開軟件如下圖
   

 

 
 

2:開啟代理抓包軟件(這里代理抓包軟件使用的是Fiddler)

  Fiddler的使用這里不再介紹,需要打開遠程代理,並在手機中安裝Fiddler根證書
  這里筆者開啟的遠程代理的地址是192.168.2.244:8888
  關於證書安裝有些細節,Fiddler默認的根證書是cer格式,部分手機可能只能識別pem格式證書
  直接使用openssl 轉一下就行了 (openssl x509 -inform der -in FiddlerRoot.cer -out FiddlerRoot.pem)
  openssl 在中 windows/mac 一般都安裝有,命令直接使用就行了,使用生成的FiddlerRoot.pem安裝到手機上就行了(Charles默認就是pem證書)
 

3:配置drony轉發

 

打開Drony(處於OFF狀態),滑動到SETING頁,點擊選擇Networks Wi-Fi 進入配置
 

 

在網絡列表中選擇點擊當前手機wifi連接的網絡 (需要確保該網絡與Fiddler代理服務器網絡是聯通的)

 

 

配置要為當前網絡使用的代理入口(這里直接填寫fiddler代理地址就可以),選擇代理模式為手動(Manual)

 

注意Proxy type代理方式要選擇 Plain http proxy

 

Filter default value 選擇 Direct all ,然后點擊下面的Rule設置應用規則

 

默認您的規則里應該是空的,這里直接點擊上面的加號添加一個規則(符合規則要求的才會被轉發)
說明一下后面的操作會以咸魚或支付寶做演示說明,不過筆者當前測試項目並不是咸魚或支付寶,也不是其公司的員工,選擇這2個APP做演示是因為這些APP比較常用,且無法抓包的原因與筆者當前項目APP是類似的。
 

 

在Network id處 選擇當前wifi的SSID
Action 選擇 Local proxy chain
Application 選擇需要強制代理的APP
Hostname 及 Port 不填 表示所有的都會被強制代理,因為APP可能會使用其他的網絡協議不一定都是http,可能不希望把所有流量都引流到http代理服務器,這個時候就會使用這個配置指定ip及端口才轉發
完成后保存即可,然后返回到SETTING主頁,滑動到LOG頁,點擊下面按鈕,使其處於ON的狀態(表示啟用)

 

 
 
這個時候啟動支付寶或咸魚,我們就可以在Fiddler上看到正常的流量。不過如果你的運氣與筆者一樣可能只能看到這些Tunnel to (TLS管道建立),如果您使用的是Charles在列表里看到的可能是一個個紅叉。
 
 

 

當然筆者Fiddler根證書是安裝成功的,Fiddler配置也是正確的(手機上的Chrome https抓包都是正常的)
既然流量已經到Fiddler了,Drony的工作算是完美完成了,之所部分APP以不能解密https報文,還是我們自己證書的問題。首先先簡單描述下證書校驗的過程(如果不想看這些過程可以直接看后面 操作步驟
 
 

證書校驗原理

無論Fiddler 或 Charles都使用中間人攻擊的方式替換tls鏈路證書,解密報文然后再加密發送給真實服務器。
您可以參看 HTTPS中間人攻擊實踐(原理·實踐)了解中間人攻擊的細節
 

 

存在代理的情況下客戶端首先連接的是代理服務器(即是圖中的攻擊者),實際client是直接與Proxy建立的TLS通道,所以代理當然TLS通道的傳輸密鑰然后解密報文。
 
不過由於證書的存在,client會校驗證書的合法性,然后決定是否連接服務器。我們使用Fiddler或Charles抓取https前在設備中安裝根證書正是為了通過client的證書校驗。
 

 

在瀏覽器中任意找一個https的網頁,查看其證書信息。
 
從這里面我們能看到證書包含以下內容:
(1) Validity也即有效期,有效期包含生效時間和失效時間,是一個時間區間;
(2) 公鑰信息Subject Public Key Info,包括公鑰的加密算法和公鑰內容;
(3) 指紋信息,指紋用於驗證證書的完整性,也是證書校驗的關鍵,他保證書沒有被修改過。 其原理就是在發布證書時,發布者根據指紋算法(此處證書使用了SHA-1和SHA-256算法 有多個指紋是為了兼容老的客戶端)計算整個證書的hash指紋【證書內容hash值使用CA私鑰加密就是指紋】並和證書放在一起,client在打開證書時,自己也根據指紋算法計算一下證書的hash值,同時使用自己信任的根證書的公鑰解密hash指紋計算出原始hash,如果hash值不一致,則表明證書內容被篡改過;
(4) 證書的簽名Certificate Signature Value和Certificate Signature Algorithm,對證書簽名所使用的Hash算法和Hash值;
(5) 簽發該證書的CA機構Issuer;
(6) 該證書是簽發給哪個組織/公司信息Subject;
(7) 證書版本Version、證書序列號Serial Number以及Extensions擴展信息等。
 
 
 

 

上圖即是證書指紋校驗的過程,可能看到Client校驗證書的核心其實是CA公鑰解密原始指紋,CA公鑰從哪里來,為了確保安全設備系統會有一批自己信任的CA公鑰列表(根證書)。這些CA公鑰對應的一般是權威機構或組織,然后由這些權威機構頒發證書時會使用他們自己的私鑰去簽名(為證書生成指紋)。這樣就確保了只有權威機構頒發給各個網站的證書才會被客戶端校驗通過。
 
Filddler沒有這些證書里公鑰對應的私鑰(CA只會把為完整頒發的證書對應的私鑰給網站的所有者),所以沒有辦法與客戶端完成TLS握手。Filddler為了完成握手只能自己為不同的站點生成證書,
不過自己的生成的證書肯定是用自己的私鑰簽名的,客戶端在自己信任的CA公鑰列表找不到對應根證書,肯定是不能通過證書校驗的。所以Filddler要求我們安裝他的根證書到設備,這樣自己簽發的證書就可以通過證書校驗,自己就能解密https報文了。
 

不能解密的原因

其實通過上面的描述也很明白了不能正常建立連接解密https報文的原因就是證書校驗失敗,我們的根證書安裝不夠完全。
從Android7.0以后,系統允許每個應用可以定義自己的 可信CA集。有部分應用默認只會信任系統預裝的CA證書,而不會信任用戶安裝的CA證書(或者說是應用使用的開發框架默認只信任系統證書,因為開發者通常不關心這些配置,也不會去更改他)。而在Android中用戶安裝的證書都是用戶證書,所以無論是Filddler還是Charles我們都只是把他們的根證書安裝到了用戶證書,這些應用並不使用他們,所以我們的安裝的證書是無效的。

 

 

解決方法及操作方法

既然又知道了原因,那就總還是有辦法去解決的。我們只要把代理軟件的根證書安裝成系統證書就可以了。
實際上將證書安裝到系統區操作還是相對簡單的,將證書用指定的名稱放到指定的位置(/system/etc/security/cacerts/)就可以了
先將我們的根證書名稱改為<Certificate_Hash>.<Number>
Certificate_Hash表示證書文件的hash值,Number是為了防止證書文件的hash值一致而增加的后綴(用0就行了)
下載自己的根證書FiddlerRoot.cer,使用openssl x509 -subject_hash_old -in <Certificate_File> 計算證書hash ,根據hash將證書重命名為 269953fb.0 (269953fb是筆者證書的hash,大家的肯定不一樣)
然后將269953fb.0文件復制到/system/etc/security/cacerts/
 

 

完成后我們就可以看到代理軟件的證書出現在系統區了。
 
這里還有一點需要單獨說明,/system/etc/security/cacerts/目錄的寫權限,需要手機root權限。
也就是說復制證書到該目錄需要您root自己的設備。
關於Android手機的root,通常手機廠家都會有自己官方的教程,建議大家按官方的操作進行root
以小米手機為例 ( http://www.miui.com/thread-12281379-1-1.html
當前小米手機的root需要手機綁定小米賬號7天以上才能解鎖,解鎖后刷入開發版即可完成root
需要注意的是不是所有小米的手機都有對應的開發版的,所以購買測試設備時留意下。( http://www.miui.com/download.html 這里可以看下自己的手機有沒有開發版可以使用)
 
效果
現在證書也被安裝到了系統區,再回到Fiddler看下效果

 

再次打開閑魚我們已經可以看到完整的https請求了。
 
下面我們找個請求修改一下請求返回數據看下效果
 
借助Fiddler插件FreeHttp修改這個請求的返回數據將二手手機修改為二手馬總並將圖片也替換掉
配置如下圖

 

 

(FreeHttp的具體使用請參考 借助FreeHttp任意篡改http報文 (使用·實現)
 

 再次打開閑魚,可以看到經過代理的數據已經被篡改了(注意測試時清除咸魚的緩存及應用數據,以保證每次打開APP都會請求firstdata)

 

經過上面到配置,這些APP的HTTP流量我們就可以通過代理抓包軟件獲取,https流量也可能正常解碼。

 

IOS設備操作步驟(IOS)

ios(iphone)同樣使用上面提到第3種方法(原理與android是一致的),同樣需要使用到VPN,在ios也有許多與drony功能類似的軟件,大家可以自己選擇自己喜歡的使用,筆者這里使用的是Shadowrocket

 

如上圖您可以直接在App Store找到這些軟件(受限於大陸相關規定,您的App Store的區域如果在國內可能無法搜索到這些軟件,您需要使用美區的賬號)

為了完成流量重新定向,Shadowrocket與drony一樣會先在設備上創建本地VPN服務,再使用您設置的規則處理流量。

不過Shadowrocket的使用會更加方便,直接打開軟件如下圖配置即可

 

  1. 選擇全局路由為「代理」
  2. 添加服務節點(類型選擇HTTP及HTTPS ,服務器地址及端口為您代理抓包工具的地址與端口)
  3. 設置狀態為啟用 (IOS會同時自動創建VPN)

現在直接打開iphone上的任意APP(不用再再wifi上重復設置代理) ,既可以在代理抓包工具上看到流量了,同樣不能解析HTTPS的流量,不過IOS並沒有像新版的android一樣可以讓APP拒絕用戶手動信任的用戶根證書,所以IOS證書安裝IOS也比android任意的多,並沒有這么多額外的操作,按正常證書安裝流程操作即可。證書安裝完成后即可查看HTTPS流量

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM