移動端防抓包實踐

楊充發表於2022-12-15

目錄介紹

  • 01.整體概述介紹

    • 1.1 專案背景
    • 1.2 思考問題
    • 1.3 設計目標
    • 1.4 收益分析
  • 02.市面抓包的分析

    • 2.1 Https三要素
    • 2.2 抓包核心原理
    • 2.3 搞定CA證照
    • 2.4 突破CA證照校驗
    • 2.5 如何搞定加解密
    • 2.6 Charles原理
    • 2.7 抓包原理圖
    • 2.8 抓包核心流程
  • 03.防止抓包思路

    • 3.1 先看如何抓包
    • 3.2 設定配置檔案
    • 3.3 資料加密處理
    • 3.4 避免黑科技抓包
  • 04.防抓包實踐開發

    • 4.1 App安全配置
    • 4.2 關閉代理
    • 4.3 證照校驗
    • 4.4 雙向認證
    • 4.5 防止掛載抓包
    • 4.6 資料加解密
    • 4.7 證照鎖定
    • 4.8 Sign簽名
    • 4.9 其他的方式
  • 05.架構設計說明

    • 5.1 整體架構設計
    • 5.2 關鍵流程圖
    • 5.3 穩定性設計
    • 5.4 降級設計
    • 5.5 異常設計說明
  • 06.防抓包功能自測

    • 6.1 網路請求測試
    • 6.2 抓包測試
    • 6.3 黑科技掛載測試
    • 6.4 逆向破解測試

01.整體概述介紹

1.1 專案背景

  • 通訊安全是App安全檢測過程中非常重要的一項

    • 針對該項的主要檢測手段就是使用中間人代理機制對網路傳輸資料進行抓包、攔截和篡改,以檢驗App在核心鏈路上是否有安全漏洞。
  • 保證資料安全

    • 透過charles等工具可以對app的網路請求進行抓包,這樣這些資訊就會被清除的提取出來,會被不法分子進行利用。
  • 不想被競爭對手逆向抓包

    • 不想自身App的資料被別人輕而易舉地抓包獲取到,從而進行類似業務或資料分析、爬蟲或網路攻擊等破壞性行為。

1.2 思考問題

  • 開發專案的時候,都需要抓包,很多情況下即使是Https也能正常抓包正常。那麼問題來了:

    • 抓包的原理是?任何Https的 app 都能抓的到嗎?如果不能,哪些情況下可以抓取,哪些情況下抓取不到?
  • 什麼叫做中間人攻擊?

    • 使用HTTPS協議進行通訊時,客戶端需要對伺服器身份進行完整性校驗,以確認伺服器是真實合法的目標伺服器。
    • 如果沒有校驗,客戶端可能與仿冒的伺服器建立通訊連結,即“中間人攻擊”。

1.3 設計目標

  • 防止App被各種方式抓包

    • 做好各種防抓包安全措施,避免各種黑科技抓包。
  • 沉澱為技術庫複用

    • 目前只是針對App端有需要做防抓包措施,後期其他業務線可能也有這個需要。因此下沉為工具庫,傻瓜式呼叫很有必要。
  • 該庫終極設計目標如下所示

    • 第一點:必須是低入侵性,對原有程式碼改動少,最簡單的加入是一行程式碼設定即可。完全解耦合。
    • 第二點:可以動態靈活配置,支援配置禁止代理,支援配置是否證照校驗,支援配置域名合法性過濾,支援攔截器加解密資料。
    • 第三點:可以檢測App是否在雙開,掛載,Xposed攻擊環境
    • 第四點:可以靈活設定加解密的key,可以靈活替換加解密方式,比如目前採用RC4,另一個專案想用DES,可以靈活更換。

1.4 收益分析

  • 抓包庫收益

    • 提高產品App的資料安全,必須對資料傳輸做好安全保護措施和完整性校驗,以防止自身資料在網路傳輸中裸奔,甚至是被三方惡意利用或攻擊。
  • 技能的收益

    • 下沉為功能基礎庫,可以方便各個產品線使用,提高開發的效率。避免跟業務解耦合。傻瓜式呼叫,低成本接入!

02.市面抓包的分析

2.1 Https三要素

  • 要清楚HTTPS抓包的原理,首先需要先說清楚 HTTPS 實現資料安全傳輸的工作原理,主要分為三要素和三階段。
  • Http傳輸資料目前存在的問題

    • 1.通訊使用明文,內容可能被竊聽;2.不驗證通訊方的身份,因此可能遭遇偽裝;3.無法證明報文的完整性,所以有可能遭到篡改。
    • image
  • Https三要素分別是:

    • 1.加密:透過對稱加密演算法實現。
    • 2.認證:透過數字簽名實現。(因為私鑰只有 “合法的傳送方” 持有,其他人偽造的數字簽名無法透過驗證)
    • 3.報文完整性:透過數字簽名實現。(因為數字簽名中使用了訊息摘要,其他人篡改的訊息無法透過驗證)
  • Https三階段分別是:

    • 1.CA 證照校驗:CA 證照校驗發生在 TLS 的前兩次握手,客戶端和服務端透過報文獲得服務端 CA 證照,客戶端驗證 CA 證照合法性,從而確認 CA 證照中的公鑰合法性(大多數場景不會做雙向認證,即服務端不會認證客戶端合法性,這裡先不考慮)。
    • 2.金鑰協商:金鑰協商發生在 TLS 的後兩次握手,客戶端和服務端分別基於公鑰和私鑰進行非對稱加密通訊,協商獲得 Master Secret 對稱加密私鑰(不同演算法的協商過程細節略有不同)。
    • 3.資料傳輸:資料傳輸發生在 TLS 握手之後,客戶端和服務端基於協商的對稱金鑰進行對稱加密通訊。
  • Https流程圖如下

    • image

2.2 抓包核心原理

  • HTTPS抓包原理

    • Fiddler、Charles等抓包工具,其實都是採用了中間人攻擊的方案: 將客戶端的網路流量代理到MITM(中間人)主機,再透過一系列的皮膚或工具將網路請求結構化地呈現出來。
  • 抓包Https有兩個突破點

    • CA證照校驗是否合法;資料傳遞過程中的加密和解密。如果是要抓包,則需要突破這兩點的技術,無非就是MITM(中間人)偽造證照和使用自己的加解密方式。
  • 抓包的工作流程如下

    • 中間人截獲客戶端向發起的HTTPS請求,佯裝客戶端,向真實的伺服器發起請求;
    • 中間人截獲真實伺服器的返回,佯裝真實伺服器,向客戶端傳送資料;
    • 中間人獲取了用來加密伺服器公鑰的非對稱秘鑰和用來加密資料的對稱秘鑰,處理資料加解密。

2.3 搞定CA證照

  • Https抓包核心CA證照

    • HTTPS抓包的原理還是挺簡單的,簡單來說,就是Charles作為“中間人代理”,拿到了伺服器證照公鑰和HTTPS連線的對稱金鑰。
    • 前提是客戶端選擇信任並安裝Charles的CA證照,否則客戶端就會“報警”並中止連線。這樣看來,HTTPS還是很安全的。
  • 安裝CA證照到手機中必須洗白

    • 抓包應用內建的 CA 證照要洗白,必須安裝到系統中。而 Android 系統將 CA 證照又分為兩種:使用者 CA 證照和系統 CA 證照(必要Root許可權)。
  • Android從7.0開始限制CA證照

    • 只有系統(system)證照才會被信任。使用者(user)匯入的Charles根證照是不被信任的。相當於可以理解Android系統增加了安全校驗!
  • 如何繞過CA證照這種限制呢?已知有以下四種方式

    • 第一種方式:AndroidManifest 中配置 networkSecurityConfig,App 信任使用者 CA 證照,讓系統對使用者 CA 證照的校驗給予透過。
    • 第二種方式:調低 targetSdkVersion < 24,不過這種方式谷歌市場有限制,意味著抓 HTTPS 的包越來越難操作。
    • 第三種方式:掛載App抓包,VirtualApp 這種多開應用可以作為宿主系統來執行其它應用,利用xposed避開CA證照校驗。
    • 第四種方式:Root手機,把 CA 證照安裝到系統 CA 證照目錄中,那這個假 CA 證照就是真正洗白了,難度較大。

2.4 突破CA證照校驗

  • App版本如何讓證照校驗安全

    • 1.設定targetSdkVersion大於24,去掉清單檔案中networkSecurityConfig檔案中的system和user配置,設定不信任使用者證照。
    • 2.公鑰證照固定。指 Client 端內建 Server 端真正的公鑰證照。在 HTTPS 請求時,Server 端發給客戶端的公鑰證照必須與 Client 端內建的公鑰證照一致,請求才會成功。

      • 證照固定的一般做法是,將公鑰證照(.crt 或者 .cer 等格式)內建到 App 中,然後建立 TrustManager 時將公鑰證照加進去。
  • 那麼如何突破CA證照校驗

    • 第一種:JustTrustMe 破解證照固定。Xposed 和 Magisk 都有相應的模組,用來破解證照固定,實現正常抓包。破解的原理大致是,Hook 建立 SSLContext 等涉及 TrustManager 相關的方法,將固定的證照移除。
    • 第二種:基於 VirtualApp 的 Hook 機制破解證照固定。在 VirtualApp 中加入 Hook 程式碼,然後利用 VirtualApp 開啟目標應用進行抓包。具體看:VirtualHook

2.5 如何搞定加解密

  • 目前使用對稱加密和解密請求和響應資料

    • 加密和解密都是用相同金鑰。只有一把金鑰,如果金鑰暴露,內容就會暴露。但是這一塊逆向破解有些難度。而破解解密方式就是用金鑰逆向解密,或者中間人冒充使用自己的加解密方式!
  • 加密後資料鎮兼顧了安全性嗎

    • 不一定安全。中間人偽造自己的公鑰和私鑰,然後攔截資訊,進行篡改。

2.6 Charles原理

  • Charles類似代理伺服器

    • Charles 透過將軟體本身設定成系統的網路訪問代理伺服器,使得所有的網路請求都會走一遍 Charles 代理,從而 Charles 可以擷取經過它的請求,然後我們就可以對其進行網路包的分析。
  • 擷取裝置網路封包資料

    • Charles對應設定:將代理功能開啟,並設定一個固定的埠。預設情況下,埠號為:8888 。
    • 移動裝置設定:在手機上設定 WIFI 的 HTTP 代理。注意這裡的前提是,Phone 和 Charles 代理裝置連結的是同一網路(同一個ip地址和埠號)。
  • 擷取Https的網路封包

    • 正常情況下,Charles 是不能擷取Https的網路包的,這涉及到 Https 的證照問題。

2.7 抓包原理圖

  • Charles抓包原理圖

    • image
  • Android上的網路抓包原來是這樣工作的

2.8 抓包核心流程

  • 抓包核心流程關鍵節點

    • 第一步,客戶端向伺服器發起HTTPS請求,charles截獲客戶端傳送給伺服器的HTTPS請求,charles偽裝成客戶端向伺服器傳送請求進行握手 。
    • 第二步,伺服器發回相應,charles獲取到伺服器的CA證照,用根證照(這裡的根證照是CA認證中心給自己頒發的證照)公鑰進行解密,驗證伺服器資料簽名,獲取到伺服器CA證照公鑰。然後charles偽造自己的CA證照(這裡的CA證照,也是根證照,只不過是charles偽造的根證照),冒充伺服器證照傳遞給客戶端瀏覽器。
    • 第三步,與普透過程中客戶端的操作相同,客戶端根據返回的資料進行證照校驗、生成密碼Pre_master、用charles偽造的證照公鑰加密,並生成HTTPS通訊用的對稱金鑰enc_key。
    • 第四步,客戶端將重要資訊傳遞給伺服器,又被charles截獲。charles將截獲的密文用自己偽造證照的私鑰解開,獲得並計算得到HTTPS通訊用的對稱金鑰enc_key。charles將對稱金鑰用伺服器證照公鑰加密傳遞給伺服器。
    • 第五步,與普透過程中伺服器端的操作相同,伺服器用私鑰解開後建立信任,然後再傳送加密的握手訊息給客戶端。
    • 第六步,charles截獲伺服器傳送的密文,用對稱金鑰解開,再用自己偽造證照的私鑰加密傳給客戶端。
    • 第七步,客戶端拿到加密資訊後,用公鑰解開,驗證HASH。握手過程正式完成,客戶端與伺服器端就這樣建立了”信任“。
  • 在之後的正常加密通訊過程中,charles如何在伺服器與客戶端之間充當第三者呢?

    • 伺服器—>客戶端:charles接收到伺服器傳送的密文,用對稱金鑰解開,獲得伺服器傳送的明文。再次加密, 傳送給客戶端。
    • 客戶端—>服務端:客戶端用對稱金鑰加密,被charles截獲後,解密獲得明文。再次加密,傳送給伺服器端。由於charles一直擁有通訊用對稱金鑰enc_key,所以在整個HTTPS通訊過程中資訊對其透明。

03.防止抓包思路

3.1 先看如何抓包

  • 使用Charles需要做哪些操作

    • 1.電腦上需要安裝證照。這個主要是讓Charles充當中間人,頒佈自己的CA證照。
    • 2.手機上需要安裝證照。這個是訪問Charles獲取手機證照,然後安裝即可。
    • 3.Android專案程式碼設定相容。Google 推出更加嚴格的安全機制,應用預設不信任使用者證照(手機裡自己安裝證照),自己的app可以透過配置解決,相當於信任證照的一種操作!
  • 尤其可知抓包的突破口集中以下幾點

    • 第一點:必須連結代理,且跟Charles要具有相同ip。思路:客戶端是否可以判斷網路是否被代理了
    • 第二點:CA證照,這一塊避免使用黑科技hook證照校驗程式碼,或者擁有修改CA證照許可權。思路:集中在可以判斷是否掛載
    • 第三點:冒充中間人CA證照,在客戶端client和服務端server之間篡改攔截資料。思路:可以做CA證照校驗
    • 第四點:為了可以在7.0上抓包,App往往配置清單檔案networkSecurityConfig。思路:線上環境去掉該配置

3.2 設定配置檔案

  • 一個是CA證照配置檔案

    • debug包為了能夠抓包,需要配置networkSecurityConfig清單檔案的system和user許可權,只有這樣才會信任使用者證照。
  • 一個是檢驗證照配置

    • 不論是權威機構頒發的證照還是自簽名的,打包一份到 app 內部,比如存放在 asset 裡。然後用這個KeyStore去引導生成的TrustManager來提供證照驗證。
  • 一個是檢驗域名合法性

    • Android允許開發者重定義證照驗證方法,使用HostnameVerifier類檢查證照中的主機名與使用該證照的伺服器的主機名是否一致。
    • 如果重寫的HostnameVerifier不對伺服器的主機名進行驗證,即驗證失敗時也繼續與伺服器建立通訊連結,存在發生“中間人攻擊”的風險。
  • 如何檢視CA證照的資料

3.3 資料加密處理

  • 網路資料加密的需求

    • 為了專案資料安全性,對請求體和響應體加密,那肯定要知道請求體或響應體在哪裡,然後才能加密,其實都一樣不論是加密url裡面的query內容還是加密body體裡面的都一樣。
  • 對資料哪裡進行加密和解密

    • 目前對資料返回的data進行加解密。那麼如何做資料加密呢?目前專案中採用RC4加密和解密資料。
  • 抓取到的內容為亂碼

    • 有的APP為了防止抓取,在返回的內容上做了層加密,所以從Charles上看到的內容是亂碼。這種情況下也只能反編譯APP,研究其加密解密演算法進行解密。難度極大!

3.4 避免黑科技抓包

  • 基於Xposed(或者)黑科技破解證照校驗

    • 這種方式可以檢查是否有Xposed環境,大概的思路是使用ClassLoader去載入固定包名的xp類,或者手動丟擲異常然後捕獲去判斷是否包含Xposed環境。
  • 基於VirtualApp掛載App突破證照訪問許可權

    • 這個VirtualApp相當於是一個宿主App(可以把它想像成桌面級App),它突破證照校驗。然後再實現掛載App的抓包。判斷是否是雙開環境!

04.防抓包實踐開發

4.1 App安全配置

  • 新增配置檔案

    • android:networkSecurityConfig="@xml/network_security_config"
  • 配置networkSecurityConfig抓包說明

    • 中間人代理之所有能夠獲取到加密金鑰就是因為我們手機上安裝並信任了其代理證照,這類證照安裝後都會被歸結到使用者證照一類,而不是系統證照。
    • 那我們可以選擇只信任系統內建的系統證照,而遮蔽掉使用者證照(Android7.0以後就預設是隻信任系統證照了),就可以防止資料被解密了。
  • 實現App防抓包安全配置方式有兩種:

    • 一種是Android官方提供的網路安全配置;另一種也可以透過設定網路框架實現(以okhttp為例)。
    • 第一種:具體可以看清單配置檔案,相當於base-config標籤下去掉 <certificates src="user" /> 這組標籤。
    • 第二種:需要給okhttpClient配置 X509TrustManager 來監聽校驗服務端證照有效性。遍歷裝置上信任的證照,透過證照別名將使用者證照(別名中含有user欄位)過濾掉,只將系統證照新增到驗證列表中。
  • 該方案優點和缺點分析說明

    • 優點:network_security_config配置簡單,對整個app網路生效,無需修改程式碼;程式碼實現對透過該網路框架請求的生效,能相容7.0以前系統。
    • 缺陷:network_security_config配置方式,7.0以前的系統配置不生效,依然可以透過代理工具進行抓包。okhttp配置的方式只能對使用該網路框架進行資料傳輸的介面生效,並不能對整個app生效。
    • 破解:將手機進行root,然後將代理證照放置到系統證照列表內,就可以繞過程式碼或配置檢查了。

4.2 關閉代理

  • charles 和 fiddler 都使用代理來進行抓包,對網路客戶端使用無代理模式即可防止抓包,如

    OkHttpClient.Builder()
        .proxy(Proxy.NO_PROXY)
        .build()
  • no_proxy實際上就是type屬性為direct的一個proxy物件,這個type有三種

    • direct,http,socks。這樣因為是直連,所以不走代理。所以charles等工具就抓不到包了,這樣一定程度上保證了資料的安全,這種方式只是透過代理抓不到包。
  • 通常情況下上述的辦法有用,但是無法防住使用 VPN 導流進行的抓包

    • 使用VPN抓包的原理是,先將手機請求導到VPN,再對VPN的網路進行Charles的代理,繞過了對App的代理。
  • 該方案優點和缺點分析說明

    • 優點:實現簡單方便,無系統版本相容問題。
    • 缺陷:該方案比較粗暴,將一切代理都切斷了,對於有合理訴求需要使用網路代理的場景無法滿足。
    • 破解:使用ProxyDroid全域性代理工具透過iptables對請求進行強制轉發,可以有效繞過代理檢測。

4.3 證照校驗(單向認證)

  • 下載伺服器端公鑰證照

    • 為了防止上面方案可能導致的“中間人攻擊”,可以下載伺服器端公鑰證照,然後將公鑰證照編譯到Android應用中一般在assets資料夾儲存,由應用在互動過程中去驗證證照的合法性。
  • 如何設定證照校驗

    • 透過OkHttp的API方法 sslSocketFactory(sslSocketFactory,trustManager) 設定SSL證照校驗。
  • 如何設定域名合法性校驗

    • 透過OkHttp的API方法 hostnameVerifier(hostnameVerifier) 設定域名合法性校驗。
  • 證照校驗的原理分析

    • 按CA證照去驗證的,若不是CA可信任的證照,則無法透過驗證。
  • 單向認證流程圖

    • image
  • 該方案優點和缺點分析說明

    • 優點:安全性比較高,單向認證校驗證照在程式碼中是方便的,安全性相對較高。
    • 缺陷:CA證照存在過期的問題,證照升級。
    • 破解:證照鎖定破解比較複雜,比如老牌的JustTrustMe外掛,透過hook各網路框架的證照校驗方法,替換原有邏輯,使校驗失效。

4.4 雙向認證

  • 什麼叫做雙向認證

    • SSL/TLS 協議提供了雙向認證的功能,即除了 Client 需要校驗 Server 的真實性,Server 也需要校驗 Client 的真實性。
  • 雙向認證的原理

    • 雙向認證需要 Server 支援,Client 必須內建一套公鑰證照 + 私鑰。在 SSL/TLS 握手過程中,Server 端會向 Client 端請求證照,Client 端必須將內建的公鑰證照發給 Server,Server 驗證公鑰證照的真實性。
    • 用於雙向認證的公鑰證照和私鑰代表了 Client 端身份,所以其是隱秘的,一般都是用 .p12 或者 .bks 檔案 + 金鑰進行存放。
  • 程式碼層面如何做雙向認證

    • 雙向校驗就是自定義生成客戶端證照,儲存在服務端和客戶端,當客戶端發起請求時在服務端也校驗客戶端的證照合法性,如果不是可信任的客戶端傳送的請求,則拒絕響應。
    • 服務端根據自身使用語言和網路框架配置相應證照校驗機制即可。
  • 雙向認證流程圖

    • image
  • 該方案優點和缺點分析說明

    • 優點:安全性非常高,使用三方工具不易破解。
    • 缺陷:服務端需要儲存客戶端證照,一般服務端會對應多個客戶端,就需要分別儲存和校驗客戶端證照,增加校驗成本,降低響應速度。該方案比較適合對安全等級要求比較高的業務(如金融類業務)。
    • 破解:由於在服務端也做校驗,在服務端安全的情況下很難被攻破。

4.5 防止掛載抓包

  • Xposed是一個牛逼的黑科技

    • Xposed + JustTrustMe 可以破解繞過校驗CA證照。那麼這樣CA證照的校驗就形同虛設了,對App的危險性也很大。
  • App多開執行在多個環境上

    • 多開App的原理類似,都是以新程式執行被多開的App,並hook各類系統函式,使被多開的App認為自己是一個正常的App在執行。
    • 一種是從多開App中直接載入被多開的App,如平行空間、VirtualApp等,另一種是讓使用者新安裝一個App,但這個App本質上就是一個殼,用來載入被多開的App。
  • VirtualApp是一個牛逼的黑科技

    • 它破壞了Android 系統本身的隔離措施,可以進行免root hook和其他黑科技操作,你可以用這個做很多在原來APP裡做不到事情,於此同時Virtual App的安全威脅也不言而喻。
  • 如何判斷是否具有Xposed環境

    • 第一種方式:獲取當前裝置所有執行的APP,根據安裝包名對應用進行檢測判斷是否有Xposed環境。
    • 第二種方式:透過自造異常來檢測堆疊資訊,判斷異常堆疊中是否包含Xposed等字串。
    • 第三種方式:透過ClassLoader檢查是否已經載入了XposedBridge類和XposedHelpers類來檢測。
    • 第四種方式:獲取DEX載入列表,判斷其中是否包含XposedBridge.jar等字串。
    • 第五種方式:檢測Xposed相關檔案,透過讀取/proc/self/maps檔案,查詢Xposed相關jar或者so檔案來檢測。
  • 如何判斷是否是雙開環境

    • 第一種方式:透過檢測app私有目錄,多開後的應用路徑會包含多開軟體的包名。還有一種思路遍歷應用列表如果出現同樣的包名,則被認為雙開了。
    • 第二種方式:如果同一uid下有兩個程式對應的包名,在"/data/data"下有兩個私有目錄,則該應用被多開了。
  • 判斷了具有xposed或者多開環境怎麼處理App

    • 目前使用VirtualApp掛載,或者Xposed黑科技去hook,前期可以先用埋點統計。測試學而思App發現掛載在VA上是推出App。

4.5 資料加解密

  • 針對資料加解密入口

    • 目前在網路請求類裡新增攔截器,然後在攔截器中處理request請求和response響應資料的加密和解密操作。
  • 主要是加密什麼資料

    • 在request請求資料階段,如果是get請求加密url資料,如果是post請求則加密url資料和requestBody資料。
    • 在response響應資料階段,
  • 如何進行加密:發起請求(加密)

    • 第一步:獲取請求的資料。主要是獲取請求url和requestBody,這一塊需要對資料一塊處理。
    • 第二步:對請求資料進行加密。採用RC4加密資料
    • 第三步:根據不同的請求方式構造新的request。使用 key 和 result 生成新的 RequestBody 發起網路請求
  • 如何進行解密:接收返回(解密)

    • 第一步:常規解析得到 result ,然後使用RC4工具,傳入key去解密資料得到解密後的字串
    • 第二步:將解密的字串組裝成ResponseBody資料傳入到body物件中
    • 第三步:利用response物件去構造新的response,然後最後返回給App

4.7 證照鎖定

  • 證照鎖定是Google官方比較推薦的一種校驗方式

    • 原理是在客戶端中預先設定好證照資訊,握手時與服務端返回的證照進行比較,以確保證照的真實性和有效性。
  • 如何實現證照鎖定

    • 有兩種實現方式:一種透過network_security_config.xml配置,另一種透過程式碼設定;

      //第一種方式:配置檔案
      <network-security-config>
      <domain-config>
          <domain includeSubdomains="true">api.zuoyebang.cn</domain>
          <pin-set expiration="2025-01-01">
              <pin digest="SHA-256">38JpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhK90=</pin>
              <!-- 備用證照資訊,一般為域名證照的二級證照 -->
              <pin digest="SHA-256">9k1a0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM90K=</pin>
          </pin-set>
      </domain-config>
      </network-security-config>
      
      //第二種方式:程式碼設定
      fun sslPinning(): OkHttpClient {
      val builder = OkHttpClient.Builder()
      val pinners = CertificatePinner.Builder()
          .add("api.zuoyebang.cn", "sha256//89KpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRh00L=")
          .add("api.zuoyebang.com", "sha256//a8za0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1o=09")
          .build()
      builder.apply {
          certificatePinner(pinners)
      }
      return builder.build()
      }
  • 該方案優點和缺點分析說明

    • 優點:安全性高,配置方式也比較簡單,並能實現動態更新配置。
    • 缺陷:網路安全配置無法實現證照證照的動態更新,另外該配置也受Android系統影響,對7.0以前的系統不支援。程式碼配置相對靈活些。
    • 破解:證照鎖定破解比較複雜,比如老牌的JustTrustMe外掛,透過hook各網路框架的證照校驗方法,替換原有邏輯,使校驗失效

4.8 Sign簽名

  • 先說一下背景和問題

    • http://api.test.com/getbanner...
    • 這種方式簡單粗暴,透過呼叫getbanner方法即可獲取輪播圖列表資訊,但是這樣的方式會存在很嚴重的安全性問題,沒有進行任何的驗證,大家都可以透過這個方法獲取到資料,導致產品資訊洩露。
  • 在寫開放的API介面時是如何保證資料的安全性的?

    • 請求來源(身份)是否合法?請求引數被篡改?請求的唯一性(不可複製)?
  • 問題的解決方案設想

    • 解決方案:為了保證資料在通訊時的安全性,我們可以採用引數簽名的方式來進行相關驗證。
  • 最終決定的解決方案

    • 呼叫介面之前需要驗證簽名和有效時間,要生成一個sign簽名。先拼接-後轉碼-再加密-再發請求!
  • sign簽名校驗實踐

    • 需要對請求引數進行簽名驗證,簽名方式如下:key1=value1&key2=value2&key3=value3&secret=yc 。對這個字串進行md5一下。
    • 然後被sign後的介面就變成了:http://api.test.com/getbanner...
    • 為什麼在獲取sign的時候建議使用secret引數?secret僅作加密使用,新增在引數中主要是md5,為了保證資料安全請不要在請求引數中使用。
  • 服務端對sign校驗

    • 這樣請求的時候就需要合法正確簽名sign才可以獲取資料。這樣就解決了身份驗證和防止引數篡改問題,如果請求引數被人拿走,沒事,他們永遠也拿不到secret,因為secret是不傳遞的。再也無法偽造合法的請求。
  • 如何保證請求的唯一性

  • Sign簽名安全性分析:

    • 透過上面的案例,安全的關鍵在於參與簽名的secret,整個過程中secret是不參與通訊的,所以只要保證secret不洩露,請求就不會被偽造。

05.架構設計說明

5.1 整體架構設計

  • 如下所示

    • image

5.2 關鍵流程圖

5.3 穩定性設計

  • 對於請求和響應的資料加解密要注意

    • 在網路上交換資料(網路請求資料)時,可能會遇到不可見字元,不同的裝置對字元的處理方式有一些不同。
    • Base64對資料內容進行編碼來適合傳輸。準確說是把一些二進位制數轉成普通字元用於網路傳輸。統統變成可見字元,這樣出錯的可能性就大降低了。

5.4 降級設計

  • 可以一鍵配置AB測試開關

    .setMonitorToggle(object : IMonitorToggle {
        override fun isOpen(): Boolean {
            //todo 是否降級,如果降級,則不使用該功能。留給AB測試開關
           return false
        }
    })

5.5 異常設計說明

  • base64加密和解密導致錯誤問題

    • Android 有自帶的Base64實現,flag要選Base64.NO_WRAP,不然末尾會有換行影響服務端解碼。導致解碼失敗。

5.6 Api文件

  • 關於初始化配置

    NotCaptureHelper.getInstance().config = CaptureConfig.builder()
            //設定debug模式
        .setDebug(true)
            //設定是否禁用代理
        .setProxy(false)
            //設定是否進行資料加密和解密,
        .setEncrypt(true)
            //設定cer證照路徑
        .setCerPath("")
            //設定是否進行CA證照校驗
        .setCaVerify(false)
            //設定加密和解密key
        .setEncryptKey(key)
            //設定引數
        .setReservedQueryParam(OkHttpBuilder.RESERVED_QUERY_PARAM_NAMES)
        .setMonitorToggle(object : IMonitorToggle {
            override fun isOpen(): Boolean {
                //todo 是否降級,如果降級,則不使用該功能。留給AB測試開關
               return false
            }
        })
        .build()
  • 設定okHttp配置

    NotCaptureHelper.getInstance().setOkHttp(app,okHttpBuilder)
  • 如何設定自己的加解密方式

    NotCaptureHelper.getInstance().encryptDecryptListener = object : EncryptDecryptListener {
        /**
         * 外部實現自定義加密資料
         */
        override fun encryptData(key: String, data: String): String {
            LoggerReporter.report("NotCaptureHelper", "encryptData data : $data")
            val str = data.encryptWithRC4(key) ?: ""
            LoggerReporter.report("NotCaptureHelper", "encryptData str : $str")
            return str
        }
        /**
         * 外部實現自定義解密資料
         */
        override fun decryptData(key: String, data: String): String {
            LoggerReporter.report("NotCaptureHelper", "decryptData data : $data")
            val str = data.decryptWithRC4(key) ?: ""
            LoggerReporter.report("NotCaptureHelper", "decryptData str : $str")
            return str
        }
    }

5.7 防抓包功能自測

  • 網路請求測試

    • 正常請求,測試網路功能是否正常
  • 抓包測試

    • 配置fiddler,charles等工具
    • 手機上設定代理
    • 手機上安裝證照
    • 單向認證測試:進行網路請求,會提示SSLHandshakeException即ssl握手失敗的錯誤提示,即表示app端的單向認證成功。
    • 資料加解密:進行網路請求,看一下請求引數和響應body資料是否加密,如果看不到實際json實體則表示加密成功。

防抓包庫:https://github.com/yangchong2...

綜合庫:https://github.com/yangchong2...

影片播放器:https://github.com/yangchong2...

相關文章