Android 系統(tǒng)各個版本上https的抓包

一、本文側(cè)重點在哪?

  1. https 的客戶端和服務(wù)器端的請求流程,加了Charles之后對請求有什么影響(中間人攻擊)
  2. 我們原來怎么抓https包的
  3. Android 7.0 (api 24 ) 和 targetSdkVersion 對抓包的影響
    開發(fā)者對自己app的抓包,
    逆向工程師對別人app的抓包
  4. 有 CA 簽名的證書訪問https的app和自簽名證書app
    微博和我們自己的app
  5. 設(shè)置 VirtualApp 為debug模式,并且設(shè)置VA 的targetSdkVersion <24

二、測試環(huán)境

  • Android EVA-AL00 7.0 API 24 華為,安裝了Charles根證書,并且設(shè)置了代理
  • Android EVA-AL00 6.0 API 23 華為,安裝了Charles根證書,并且設(shè)置了代理
  • 微博客戶端,微博熱搜榜接口,這個接口當(dāng)時是用oppo測試機抓的不用關(guān)心里面的參數(shù),能用就行
  • 網(wǎng)絡(luò)請求框架 okhttp3

三、https 通信過程和中間人攻擊

下圖是https 客戶端和服務(wù)器端通信的基本流程

https 通信過程.png

那么如何抓包呢,原理其實說起來也很簡單,就是在客戶端給服務(wù)器端發(fā)消息的時候,中間人(Charles)截取客戶端發(fā)送給服務(wù)器的請求,然后偽裝成客戶端與服務(wù)器進行通信;將服務(wù)器返回給客戶端的內(nèi)容發(fā)送給客戶端,偽裝成服務(wù)器與客戶端進行通信。

其實Charles就是這么做的,當(dāng)配置了Charles之后,理論上所有的http/https請求數(shù)據(jù)都被攔截到了??聪旅嬉粡埡喕闹虚g人抓包的圖:

中間人抓包圖.png

四、我們原來怎么抓https包的

分為三步

  1. 手機上導(dǎo)入Charles根證書,導(dǎo)入方式見Charles官網(wǎng)

    Charles導(dǎo)入根證書到Android設(shè)備上.png

  2. 電腦端Charles設(shè)置https抓包配置
    菜單欄 Proxy -->ProxySetting


    電腦端Charles設(shè)置.png
  3. 手機端配置代理


    手機端配置代理.png

理論上來說按照上面的配置,配置之后,然后手機上安裝新浪微博客戶端之后就能抓到微博的數(shù)據(jù)了。我們分別用Android6.0 和 Android7.0 的手機打開微博客戶端看下效果:

發(fā)現(xiàn)在6.x系統(tǒng)上,微博打開正常,并且Charles顯示列出了已經(jīng)抓到的微博的接口api。

但是在Android 7.x操作系統(tǒng)上,微博顯示網(wǎng)絡(luò)出錯啦,請點擊按鈕重新加載如下圖:

Android 7.X系統(tǒng)微博抓包失敗

而且Charles上顯示確實抓到了包,但是報錯You may need to configure your browser or application to trust the Charles Root Certificate. See SSL Proxying in the Help menu.,Charles說手機端沒有信任Charles的根證書,但是我們手機上已經(jīng)安裝了Charles根證書了,為什么會這樣?

原來在Android 7.0(API 24 ) ,有一個名為“Network Security Configuration”的新安全功能。這個新功能的目標(biāo)是允許開發(fā)人員在不修改應(yīng)用程序代碼的情況下自定義他們的網(wǎng)絡(luò)安全設(shè)置。如果應(yīng)用程序運行的系統(tǒng)版本高于或等于24,并且targetSdkVersion>=24,則只有系統(tǒng)(system)證書才會被信任。所以用戶(user)導(dǎo)入的Charles根證書是不被信任的。具體說明看官方文檔在這個官方文檔里面說了,如何能指定信任用戶安裝的根證書從而可以實現(xiàn)抓包。

五、Android 7.0 (api 24 ) 和 targetSdkVersion 對抓包的影響

這里要分兩種情況:

  • 抓自己開發(fā)的app的網(wǎng)絡(luò)包
  • 抓第三方app的網(wǎng)絡(luò)包,比如微博客戶端

這兩種情況有什么區(qū)別的,第一種app是我們自己開發(fā)的,我們手里有源碼,能夠修改,能夠做到像官方文檔里面說的一樣進行配置。第二種我們沒有源碼,要想做到像官方文檔里面配置的話,只能反編譯后,把配置文件添加進去然后重新打包,但是重新打包就會遇到很多坑,并不一定能成功,所以需要使用其他方式達到抓包目的。

引用官方文檔一句話:默認(rèn)情況下,來自所有應(yīng)用的安全連接(使用 TLS 和 HTTPS 之類的協(xié)議)均信任預(yù)裝的系統(tǒng) CA,而面向 Android 6.0(API 級別 23)及更低版本的應(yīng)用默認(rèn)情況下還會信任用戶添加的 CA 存儲。應(yīng)用可以使用 base-config(應(yīng)用范圍的自定義)或 domain-config(按域自定義)自定義自己的連接。

如何能在Android 7.0 上成功的抓自己開發(fā)的app的https的包

目前我常用的有三種方式:

  1. 操作系統(tǒng),通過apk里面的配置文件控制app的證書信任機制

Android 官方文檔里的配置方式進行配置,文檔里面講的很詳細,7.0之后對于自己app可選擇的可信任的證書鏈控制很細。我這里只添加一種方式,讓我們自己開發(fā)的app能夠信任Android手機上用戶導(dǎo)入的根證書。

如下圖所示,手機的根證有兩種,一種是系統(tǒng)預(yù)裝的,一種是用戶自己導(dǎo)入的:


手機上的證書分為兩種.png

配置方式:

添加如下文件 res/xml/network_security_config.xml 到你的代碼里面,然后就能實現(xiàn)debug模式下,信任用戶自己安裝的根證書,比如Charles的證書:

<network-security-config> 
  <!-- Trust user added CAs while debuggable only -->
  <debug-overrides> 
    <trust-anchors> 
      <!--信任用戶安裝的證書-->
      <certificates src="user" /> 
    </trust-anchors> 
  </debug-overrides> 
</network-security-config>

然后在你 app的 manifest 文件中引入上面的文件, 如下所示:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:networkSecurityConfig="@xml/network_security_config" ... >
        ...
    </application>
</manifest>

然后配置好之后,這樣就可以直接訪問,https請求,并且通過Charles抓包了。

  1. 降低 targetSdkVersion 的版本來繞過Android 7.0(api 24)上網(wǎng)絡(luò)的安全機制
    如果我們不想像上面一樣配置這么復(fù)雜的東西,可以通過降低targetSdkVersion的方式來達到一樣的效果,在gradle文件中配置 targetSdkVersion < 24 就可以了,但是這玩意在以后開發(fā)規(guī)范中有可能是不允許的。
defaultConfig {
        applicationId "me.febsky.okhttp.test"
        minSdkVersion 19
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

網(wǎng)絡(luò)請求測試代碼如下,別忘了配置manifest文件中申請網(wǎng)絡(luò)請求權(quán)限:

package me.febsky.okhttp.test;

import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread() {
            @Override
            public void run() {
                super.run();

                String url = "https://api.weibo.cn/2/guest/cardlist?" +
                        "networktype=wifi&uicode=10000327&moduleID=708&checktoken=" +
                        "&c=android&i=a52f1e4&s=c1108e87&ua=OPPO-OPPO%20R9m__weibo__6.8.2__android__android5.1" +
                        "&wm=9847_0002&aid=01AilAKZLB81znjKciZxofmqIMYg52EReWuEaQL7hIDXj6IR4." +
                        "&did=b87cc255f19b91ff8e202968adab0eb9fc159a2e&&v_f=2&v_p=33" +
                        "&from=1068295010&gsid=_2AkMg6ZSSf8NhqwJRmP0QzGPgb4l_wgjEieLBAH7sJRM3HRl-3T9jqnUstRUyD-wT6lM3A4HWHM1fFXBWuOYnxg.." +
                        "&lang=zh_CN&page=1&skin=default&count=20&oldwm=9893_0044" +
                        "&sflag=1&containerid=1087030002_2982_2_50&need_head_cards=0";

                OkHttpClient okHttpClient = new OkHttpClient.Builder()
                        .connectTimeout(10, TimeUnit.SECONDS)
                        .writeTimeout(10, TimeUnit.SECONDS)
                        .readTimeout(10, TimeUnit.SECONDS)
                        //.sslSocketFactory()
                        .build();

                Request request = new Request.Builder()
                        .url(url)
                        .build();

                okHttpClient.newCall(request).enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        Log.e("Q_M", "GET -->" + e.toString());

                    }

                    @Override
                    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                        Log.d("Q_M", "GET -->" + response.body().string());
                    }
                });
            }
        }.start();
    }
}
  1. 修改http請求框架的協(xié)議棧,讓框架不驗證證書

這里我們用的是okhttp的網(wǎng)絡(luò)請求框架,如何添加信任證書或者,不驗證證書,可以參考官網(wǎng)文檔,或者自行搜索。這會因為你使用的框架不同而不同。現(xiàn)在的開發(fā)者一般沒人這么用吧,這么用了,還特么用啥https ????!

如何在Android 7.X 以上系統(tǒng)中抓第三方app的https包

一般情況下第三方我們都是抓第三方app的包,是為了分析別人的數(shù)據(jù)。但是像上面所說的前兩種方式一般在第三方app上不會存在的,誰也不想讓自己的app被抓包不是。

  1. 我們可以通過重打包的方式強行修改配置,或者強行降低 targetSdkVersion,或者強行修改別人源碼里面的信任證書的代碼,然后再重打包就好了(分別針對上面1,2,3里面所說的方法,只不過通過逆向的方式添加)。

  2. 通過使用Xposed的 JustTrustMe 模塊來信任所有的證書,Xposed不會用的看這里

  3. 有點偽~~,使用Android 7.0 以下的系統(tǒng)安裝應(yīng)用,并抓包

  4. 使用雙開沙箱應(yīng)用,比如VirtualApp,讓被抓包的應(yīng)用運行到VA里面,并且修改VA的targetSdkVersion < 24,或者通過Manifest文件里面配置networkSecurityConfig屬性,讓他信息Charles證書。

  5. 把 Charles 證書,打入到Android 系統(tǒng)信任證書里面去

六、使用自簽名證書的應(yīng)用和雙向驗證的應(yīng)用

在抓取一些第三方應(yīng)用的包的時候,他們比較頑固:其一呢,客戶端通過指定的方式只信任某一個證書;其二,我們一般來說只有客戶端驗證服務(wù)端公鑰證書是不是合法,但是某些app,比如支付寶,采用雙向驗證的方式,在通信過程中,服務(wù)器會驗證app的公鑰證書,這時候,就沒辦法使用Charles(中間人攻擊的方式)抓包了。

自簽名證書的https和CA簽名的https 區(qū)別在哪里?對https請求的影響又在哪里?關(guān)于這些問題建議了解些證書和CA相關(guān)的概念以及證書分發(fā)的流程。

從前面的https 客戶端和服務(wù)器端通信的時序圖中可以看到,在握手過程中客戶端會驗證服務(wù)器的公鑰證書。如果證書驗證不通過會終止請求。那么問題來了,證書合不合法誰說了算?一般來說,在Android 手機出廠的時候會預(yù)裝一些證書,這些證書是CA的根證書,理論上來說默認(rèn)是可信任的。如上圖:手機上的證書分為兩種.png 里面的系統(tǒng)列表的證書就是。對于網(wǎng)站來說,這個驗證過程是由瀏覽器來做的,瀏覽器通過系統(tǒng)里面預(yù)裝的CA的根證書來驗證這個服務(wù)器的證書是不是由系統(tǒng)已經(jīng)有的這些CA簽發(fā)的。如果是那么就認(rèn)為這個https的請求中的服務(wù)器證書是可信的。

但是話說回來,我們在開發(fā)app的時候,請求網(wǎng)絡(luò)一般用的是網(wǎng)絡(luò)框架,這靈活性就比較好了,大多數(shù)的網(wǎng)絡(luò)請求框架(HttpClient,OkHttp等)都支持修改這個證書驗證過程,就是我不用上面所說的瀏覽器驗證證書的過程,修改框架里面這個驗證過程,(因為CA簽發(fā)證書是要花錢的好多公司都是用的自簽名的證書)指定框架在驗證的時候只會認(rèn)為和我們公司一樣的證書才認(rèn)為驗證成功,才能進行接下來的通信。

其實上面 通過使用Xposed的 JustTrustMe 模塊來信任所有的證書,Xposed不會用的看這里 就是針對這些網(wǎng)絡(luò)請求框架進行攻擊的 通過hook的方式強制讓這些網(wǎng)絡(luò)框架信任所有的證書。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容