Https通訊原理及Android中實用總結

1、背景

Http儼然已經成爲互聯網上最普遍使用的應用層協議,隨着應用形態的不斷演進,傳統的Http在安全性上開始面臨挑戰,Http主要安全問題體如今:
1,信息內容透明傳輸。
2,通訊對方的身份不可安全驗證。
3,通訊信息可能被篡改。php

因而,結合SSL/TLS協議,造成的Https,被普遍使用。Https如今已經成爲業內安全的Http協議的事實標準。html

不管是Web前端,仍是Android,或iOS客戶端等終端,與服務端進行Https通訊時,通訊過程與原理都是相通的,面對須要解決的問題也大同小異。本文主要經過梳理Https通訊過程,並總結其在Android中的實際應用,加深對Https的理解。前端


2、Https通訊過程

Https涉及到的知識點不少,若是是完整的舊項目從Http遷移到Https,過程也會相對複雜。本文更多的從客戶端的視角,去梳理與Https密切相關的知識體系。其中,加密算法、散列算法,數字證書等,都是很是重要的技術點。java

2.1 對稱加密

對稱加密,對於加密和解密算法來講,加密和解密的密鑰是相同的,如同同一把鎖,加密密鑰和解密密鑰都是相同的一把鑰匙。用密鑰加密後,獲得加密後的密文,隨後能夠直接用其進行解密,獲得初始的原文。android

對於通訊的雙方,經過對稱加密,能夠很方便的將通訊內容進行加密,而後進行安全傳輸,可以有效的防止信息在中途被中間人獲取到原文。即便信息中途有被截獲的可能,但只要密鑰沒有泄露,信息自己仍是安全的。git

鑑於安全、方便、高效等特色,對稱加密被普遍的使用在信息傳輸過程當中。github

2.2 非對稱加密

對稱加密存在最大的一個問題,在於如何將對稱密鑰安全的告知到對方。在一個客戶端能夠同時和多個服務端通訊,一個服務端能夠同時和多個客戶端通訊的現實環境下,這種關係是多對多的,而對稱密鑰又只能由當前通訊的客戶端和服務端所持有,所以,在實際通訊過程當中,對稱密鑰的協商成爲現實中難點。算法

與對稱加密不一樣的是,非對稱加密同時具備公鑰和私鑰。若是用公鑰進行加密,則只能經過對應的私鑰去解密,若是用私鑰進行加密,則只能經過對應的公鑰去解密。 在非對稱加密體系中,公約和私鑰是一對活寶,缺乏任何一方都是不能夠的。私鑰每每都主體對象本身保留,公鑰則能夠直接向外界公開。瀏覽器

公私玥的存在,使得非對稱加密具備了相對對稱加密明顯的優勢。
1,公鑰直接向外界公開,外界任一主體經過公鑰進行加密,能夠直接向持有私鑰的主體安全的發送加密後的密文,私鑰主體拿到密文後,經過自身持有的私鑰對應解密,獲取明文,以此完成信息的安全傳輸過程,且無須面臨對稱加密中對稱密鑰的安全協商問題。緩存

2,私鑰主體經過私鑰對信息進行加密,外界任一主體經過公鑰去進行解密,若是能夠成功解密,則能反向肯定對應通訊對方的身份,至關於完成了身份校驗。以此,非對稱加密具備很好的身份驗證能力。

凡事有利有弊,非對稱加密相比對稱加密,由於自己功能更增強大,在算法設計上對對應的也更加複雜,在加解密效率上,遠低於對稱加密。

2.3 散列算法

散列算法,也稱之爲摘要算法或哈希算法,能夠將任一數據對象壓縮成數據摘要,對於同一散列算法,壓縮後的數據摘要具備特定的長度和格式,以此造成數據的「指紋」。原始數據對象的任一細小改動,均可能使得新的「數字指紋」有着很大不一樣。

每每經過散列算法,能夠判斷兩個數據對象是否相同,由於相同的數據對象,經過散列算法造成的「數字指紋」一定是相同的。可是相同的「數字指紋」,對應的原始數據對象不必定是相同的,由於可能存在散列衝突問題。

散列算法,在現實中就有普遍的使用場景,例如最經常使用的對兩個文件對象進行MD5,判斷其內容是否相同。

嚴格意義上來講,散列算法與加密算法(對稱加密或非對稱加密)是有着本質區別的,加密算法,對應的是能夠解密的,目的是進行數據加密後的安全存儲或傳輸,是能夠經過密鑰獲得原文的,是可逆的過程。而散列算法,本質上「數字指紋」的範疇,經過散列算法造成的「數字簽名」,直接在算法層面是不能獲得原文的,是不可逆的。固然,經過彩虹表或數據字典這種形式的所謂解密,本質上只是暴力破解的過程。

2.4 Https通訊流程

Https = Http + SSL/TLS = Http + 內容加密 + 身份驗證 + 數據完整性保護。當前,TLS主要使用的版本是1.2,按照RFC官網,Https通訊過程示意以下:

完整的具體過程能夠參照下圖(來源:wiki):

從總體上看,Https通訊過程包含了祕鑰協商和加密通訊兩個階段。

2.4.1 祕鑰協商

祕鑰協商是整個Https通訊過程當中的重點部分。此處的祕鑰,指的是客戶端與服務端協商後續用於信息加密的對稱祕鑰。協商的主要過程包括:
1,客戶端向服務端發送ClientHello消息,其中包含客戶端隨機生成的隨機數RNc,客戶端的協議版本信息、加密套件信息等。
2,服務端接收消息,並向客戶端發送ServerHello消息,其中包括服務端隨機生成的隨機數RNs,服務端協議版本信息,加密套件等信息。
3,服務端向客戶端發送包含了服務端公鑰的證書。
4,服務端向客戶端請求包含了客戶端公鑰的證書。
5,客戶端覈驗服務端證書,並向服務端發送包含了客戶端公鑰的客戶端證書。
6,服務端覈驗客戶端證書。
7,客戶端生成隨機數PMS,並經過服務端公鑰將PMS進行加密,發送給服務端。
8,客戶端和服務端經過一樣的算法,以及RNc,RNs,PMS,分別生成對稱加密祕鑰,由於算法和參數都是相同的,所以,兩端生成的對稱祕鑰也是相同的。

以此完成兩端對稱祕鑰的協商過程。

2.4.2 加密通訊

祕鑰協商完成後,SSL握手過程結束。後續的通訊過程都基於協商了的對稱祕鑰進行加密,在進行傳輸。這個過程與通常意義上的加密通訊過程沒有差異。

祕鑰協商的最終目的,是在客戶端和服務端安全的同時生成用於後續加密通訊過程的對稱祕鑰。這也正是Https所謂的安全的根本。

2.5 CA及數字證書

祕鑰協商過程當中,客戶端和服務端如何安全的交換彼此的非對稱加密的公鑰成爲重點。由於一旦安全的獲知對方的公鑰後,就能夠經過對方公鑰進行加密,進一步完成後續對稱祕鑰的協商。在得到對方公鑰時,如何對通訊對方身份進行覈驗,以確保此公鑰就是真實的通訊對方的公鑰?

公鑰不可能直接經過網絡進行傳輸,不然依然存在信息被中間竊取和篡改的可能,進一步可能引起中間人攻擊。所以,在得到對方公鑰的同時,還能有一套機制去核驗對方的身份,以及對方公鑰的準確性,是一大難點。

直接經過網絡方式,將永遠是一個雞生蛋和蛋生雞的問題,安全性永遠無法獲得保障。由此,經過基於CA的方式,頒發數字證書,來對通訊方的身份進行「擔保」,對數據完整性提供覈驗,被設計出來。

經過信任CA,由此信任CA頒發的數字證書,
由此信任通訊方並獲取到對方的公鑰。
複製代碼

對應的,如今存在兩個問題:
1,CA自己的身份,如何信任?
2,信任CA後,如何校驗數字證書以確認通訊對方的身份並獲取到對應的公鑰?

實際應用中,對CA身份的信任,提供了兩種途徑。一種是直接基於系統的集成,將全球主要的CA自己對本身簽發的數字證書集成到系統中。如Mac電腦系統或Android手機等。另外一種是基於人爲的手動授信,如經過瀏覽器下載第三方的CA數字證書,並設置對其進行信任。不管是哪一種方式,系統將會對集成了的CA數字證書信任,並能獲取到對應的CA公鑰。

接下來以客戶端校驗服務端證書爲例,闡述完整的身份覈驗和公鑰獲取過程。

管理員向CA申請數字證書,其中包括服務端公鑰,域名,證書有效期,組織機構,地域,證書序列號,頒發機構等信息。這些信息正文,經過散列算法H,造成信息摘要,CA對生成的信息摘要,經過CA自身的非對稱加密的私鑰進行加密,獲得密文,此密文稱之爲數字簽名(CA對信息摘要進行了簽名),信息正文、數字簽名,放在一塊兒,造成數字證書。

數字證書上,包括兩大內容:
1,信息正文
2,數字簽名。
複製代碼

服務端將證書發送給客戶端後,客戶端首先拿到證書的CA信息,與系統中已經授信的證書CA進行比較,若是發現存在一樣的CA,則使用CA的公鑰對其進行解密。不然將嘗試基於證書鏈的形式對服務端證書CA的身份進行驗證,經過後再基於CA公鑰進行解密。不然,服務端證書校驗失敗。

CA公鑰解密數字證書上的數字簽名後,能夠獲得消息摘要,再經過對信息正文進行一樣的散列算法,也獲得消息摘要,將兩個消息摘要進行對比,以完成數據完整性的校驗。同時,服務端身份以及數字證書上的服務端公鑰也得以確認。


3、Https抓包原理及Charles實踐

3.1 中間人攻擊

Https抓包,本質上是基於中間人攻擊。安裝好抓包軟件,開啓抓包服務,將客戶端(手機或瀏覽器等)配置好相應的代理服務器地址及端口。此時,客戶端的Http/Https請求將經過抓包服務中轉,對Http/Https通訊服務端而言,抓包服務充當了客戶端角色,對源客戶端而言,抓包服務充當了服務端角色。所以,抓包服務造成事實上的代理,且同時具備正向代理和反向代理的職能。

通訊通過抓包服務,但對於Https請求,因爲報文主體是加密的,此時雖然能抓到包,但看到報文主題是亂碼形式。由於此時抓包服務沒法對報文主體進行透明解密,也沒法達到能夠篡改的效果。此時,針對報文主體,更多的扮演的是一箇中間代理轉發通訊的角色。由於此時,客戶端對通訊服務端的身份依然既有有效的核驗過程。

在使用抓包軟件時,都會要求客戶端安裝一個證書並設置信任。這個證書,就是抓包服務所對應的證書,客戶端信任此證書後,至關於徹底信任了抓包服務。此時,抓包服務具有了完整意義上的通訊中轉、分發、信息透明和篡改等功能,達到了完整意義上中間人攻擊的效果。源客戶端和源服務端實際上將再也不是和對方通訊,只是他們覺得,通訊方仍是彼此。

信任了抓包服務的證書,此後,源客戶端實際上,是在和抓包服務進行通訊,對服務端的身份和信息完整性校驗,也是基於抓包服務的公鑰。源客戶端的請求,對抓包服務將是徹底透明的,抓包服務能夠篡改此請求,並扮演成源客戶端角色,和源服務端通訊,由於抓包服務具備源服務端的公鑰和協商後的對稱加密祕鑰,所以,服務端返回的結果,對抓包服務是透明的,抓包服務能夠對其進行篡改,並返回給源客戶端。這也是不少抓包工具,不但具備對通訊內容的透明顯示,也還具備額外的調試功能,如經過對請求參數,或返回結果等的修改,達到想要的調試目的等。

主流的Http/Https抓包工具備Fiddler、Charles等。Mac上用的較多的通常是Charles。下面主要總結下Charles實踐部分。

3.2 Charles破解

當前官方版本的Charles 是收費軟件,有30天的免費試用時間,即便試用期事後,未付費的用戶仍然能夠繼續使用,可是每次使用時間不能超過 30 分鐘,而且啓動時將會有 10 秒種的延時。實際使用過程當中有點不太方便。可能用着用着,須要你重啓。

網上提供了不少Charles破解的資料,在此只是作一個總結,平時使用請支持正版。

最新Charles版本是v4.2.8。

3.2.1 Charles破解工具

Charles在線破解工具:
www.zzzmode.com/mytools/cha…
對應的還有一個歷史版本的破解說明和Github項目地址:
blog.zzzmode.com/2017/05/16/…
github.com/8enet/Charl…

RegisterName輸入本身喜歡的註冊名,而後選擇本身本機已經安裝的Charles版本,點擊「生成」,下載對應生成的charles.jar文件。

覆蓋本機對應Charles安裝文件。/Applications/Charles.app/Contents/Java/charles.jar 重啓Charles,發現顯示「Registered to: corn」,且已經正式激活。

3.2.2 Charles破解原理

Charles對因而否破解的判斷,是寫在charles.jar文件中的,找到混淆後的對應class文件,將對應破解判斷的邏輯,經過修改字節碼的方式強制改爲已經註冊邏輯,而後從新生成charles.jar文件。

3.2.3 Beyond Compare比較.class文件

具體能夠經過Beyond Compare對比兩個charles.jar文件,看看具體差別在什麼地方。

Beyond Compare默認不支持.class格式的文件比較。所以,默認狀況下,若是直接比較,能夠發現惟一差別的文件爲:qHTb.class,但文件中的內容是識別不了的,以相似亂碼形式展現。

Beyond Compare默認支持的文件格式能夠經過Beyond Compare >> 文件格式...查看。默認不支持.class格式的文件,咱們能夠添加其對.class格式的文件支持。

網址:www.scootersoftware.com/download.ph… 上提供了其餘的文件格式,咱們能夠對應搜索並下載後,經過工具 >> 導入配置...給配置進來,以此支持此類文件文件。但.class文件格式只提供了Windows平臺的支持,Mac下沒有提供。

不過,咱們能夠經過配置文件格式爲外部程序轉換的方式進行額外的格式支持。上述Windows平臺中的.class文件支持中,具體能夠看到以下描述:

Java class to source8-Feb-2019 *.class 
- Compares Java class files decompiled to source. 
- - Uses Java decompiler, Jad: http://varaneckas.com/jad
複製代碼

所以,咱們也能夠經過直接配置jad的方式,直接對比.class文件。

a, http://varaneckas.com/jad對應的jad版本,解壓後放置到系統合適目錄下,如/Users/corn/Research/jad158g/
b,Beyond Compare >> 文件格式... >> 新增格式化文件General中配置*.class,Conversion中勾選上外部程序,並配置上對應的外部程序命令:/Users/corn/Research/jad158g/jad -p %s >%t

c,再次對比 qHTb.class,發現已經能夠直接對比查看了(若是還不行試着選擇導航中的 Format >> class文件)。

咱們發現,破解的charles.jar,只是修改了qHTb.class字節碼中的DdNM()方法,直接返回了true,此爲校驗是否註冊的方法。另外一個方法是gbef(),此爲獲取註冊名的方法。

由此,經過強制修改字節碼的方式將對應邏輯改爲已經註冊,完成破解。

3.3 Charles抓包注意點

Charles抓包,網上實際上有不少文章,都有專門闡述,此處主要總結下抓包過程當中,須要注意的地方:
1,源客戶端,須要安裝後Charels對應的證書,並對其信任。具體過程參考菜單Help >> SSL Proxying中。
2,須要具體配置好Proxy Setting,且SSL Proxy Setting也要配置好,這一點常常容易忘。若是想全部的包,能夠直接配置*。但須要特別注意的是,若是勾選上Proxy >> MacOS Proxy後,設置的是系統代理模式,可能會對系統的其餘軟件的使用形成影響,例如Android Studio。由於此時,AS也極可能走對應的代理(由於可能有緩存)。固然,若是須要抓包國外的一些被牆了的域名地址,也能夠經過設置External Proxy Settting ...形式走外部的其餘的代理。
3,經過Start Recording,開啓抓包。抓包過程當中能夠進行延遲、斷點、rewriteMap Remote/Local等各類調試技巧。斷點不必定有效,由於實際中,發現每每會延遲。rewrite、Map實際中,很是有用,例如和服務端聯調等。
4,有些狀況下,源客戶端是能夠禁掉抓包服務的,例如配置上不使用代理等。此時,Charles等抓包服務將會失效。


4、Android防抓包原理及總結

Android開發中,經過抓包分析競品App的通訊信息,是很常見的。但每每也發現,有些App,是抓不了包的。爲了自身App的安全性等考慮,正式對外發布的安裝包,有必要作防抓包處理。

抓包的本質,是中間人攻擊。針對中間人攻擊的原理,在其中關鍵環節,打破抓包工具成爲完整意義上中間人的條件,即可以實現Android App的防抓包防禦。

1,源客戶端忽略代理設置。
Android項目中,能夠經過判斷當前是否在使用代理,經過忽略掉代理設置,實現請求的直接鏈接。
通常的對是否使用代理的判斷寫法以下:

/**
 * 判斷是不是在代理環境下
 *
 * @return
 */
private boolean isUsingProxy() {
    // 是否大於等於14
    final boolean isIceOrUpper = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
    String proxyAddress;
    int proxyPort;

    if (isIceOrUpper) {
        proxyAddress = System.getProperty("http.proxyHost");
        String portStr = System.getProperty("http.proxyPort");
        proxyPort = Integer.parseInt((portStr != null ? portStr : "-1"));
    } else {
        proxyAddress = Proxy.getHost(BaseApplication.context);
        proxyPort = Proxy.getPort(BaseApplication.context);
    }

    return (!TextUtils.isEmpty(proxyAddress)) && (proxyPort != -1);
}
複製代碼

OkHttp直接提供了忽略代理設置的接口。若是發現正在使用代理,能夠設置忽略代理。

OkHttpClient.Builder builder = new OkHttpClient.Builder();
...
builder.proxy(Proxy.NO_PROXY);
....
複製代碼

2,源客戶端設備提升證書信任級別。
Android 7.0開始,將網絡安全配置中的證書由原來的「系統級證書」和「用戶級證書」改爲了「系統級證書」。這也就意味着,「用戶級證書」默認將不被信任,即便用戶本身,已經設置了對其信任。所以,咱們會發現,默認狀況下,在Android 7.0及以上手機上,是抓不了包的。
抓包代理顯示的信息爲:

源客戶端顯示的信息爲:

Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
        at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:661)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:539)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:605)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:495)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:418)
        at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:339)
        at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
        at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:88)
        at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:197)
        at com.android.org.conscrypt.ConscryptFileDescriptorSocket.verifyCertificateChain(ConscryptFileDescriptorSocket.java:399)
        at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
        at com.android.org.conscrypt.SslWrapper.doHandshake(SslWrapper.java:374)
        at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:217)
        ....
複製代碼

同時,Android對開發者提供了網絡安全配置入口,若是須要抓包,只須要將「用戶級證書」加入到對應配置項便可。

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="user" />
            <certificates src="system" />
        </trust-anchors>
    </base-config>
</network-security-config>
複製代碼

<certificates src="user" />是配置的重點,表示「用戶級證書」可被信任。
開發過程當中,或內部的測試包,可能須要抓包,所以,對內環境開啓此配置項是頗有必要的。但對外的正式包中,應該保持系統本來配置,以提高抓包防禦的安全級別。

針對不一樣場景下的網絡安全配置需求,官方文檔也給出瞭解決方法,例如提供了android:debuggable爲true狀況下的專門配置。但實際App開發中,每每此開關都直接是false配置的,解決方法也很簡單,能夠針對App的buildTypesproductFlavors甚至變體去單獨配置network-security-config便可。如針對對內的dev環境下配置上<certificates src="user" />,以使得能夠抓包,對外環境下去掉此配置。

3,源客戶端增強對服務端的信任校驗。 源客戶端增強對服務端的信任校驗,實際中根據具體的需求場景,服務端證書的配置方式等,能夠有多種方式。例如源客戶端內置上服務端證書,或者對服務域名進行安全校驗,又或者對證書名稱進一步校驗等。一旦發現不符合預期的證書信息項,則終止對應請求。

下面簡單演示對服務端信息判斷,一旦是抓包服務信息,則終止掉請求。

public class ServerCertificateSecurityVerifier implements HostnameVerifier {
    ....
    
    private static final String[] DEFAULT_INSECURITY_CA_ISSUER_KEYWORDS = new String[]{
            // fiddler
            "fiddler.com",
            // fiddler
            "fiddler2.com",
            // charles
            "charlesproxy.com",
            // whistle
            "wproxy.org",
            // Android Packet Capture
            "Packet Capture CA Certificate",
            // mitmproxy
            "mitmproxy",
            // debug proxy
            "Debug Proxy"
    };
    
    @Override
    public boolean verify(String hostname, SSLSession session) {
        // 不容許抓包條件下,判斷正式信息是否包含主流的抓包代理,若是,校驗失敗,不然,走默認流程
        try {
            for (X509Certificate x509Certificate : session.getPeerCertificateChain()) {

                if (x509Certificate.getIssuerDN() == null || StringUtil.isEmpty(x509Certificate.getIssuerDN().getName())) {
                    continue;
                }

                String caIssuerCompleteName = x509Certificate.getIssuerDN().getName();
                for (String insecurityCAIssuerKey : mInsecurityCaIssuerKeywords) {
                    // 證書信息中有抓包工具的證書信息
                    if (Pattern.compile(Pattern.quote(insecurityCAIssuerKey), Pattern.CASE_INSENSITIVE)
                            .matcher(caIssuerCompleteName).find()) {
                        Log.w(, TAG, "ServerCertificate error... - " + caIssuerCompleteName);
                        return false;
                    }
                }

            }

        } catch (Exception e) {
            Log.e(TAG, e);
        }
        return verifyByOkHttpDefault(hostname, session);
    }
複製代碼

5、結語

網絡請求的安全性問題如今愈發獲得重視,Google和Apple也明確要求在其應用市場上上架的App都必須遵循Https安全標準。Google Play渠道上架的條款中,也明確規定,對於邏輯中可能存在的中間人攻擊行爲,須要作進一步的安全處理,不然不能上架成功。從Android 7.0開始提高系統默認狀況下只支持「系統級證書」等行爲上看,Https的安全要求和標準也會不斷提升。平時Android App開發過程當中,與服務端通訊過程當中涉及到的安全性問題,還有不少實際的場景,基於Https基礎上,須要作進一步的加密處理或安全校驗,以儘量的提升App安全防禦級別。





參考網址:
tools.ietf.org/html/rfc524…
developer.android.com/training/ar…
codelabs.developers.google.com/codelabs/an… mp.weixin.qq.com/s/3M0CqFQP2…
zh.wikipedia.org/wiki/傳輸層安全性…
zh.wikipedia.org/wiki/超文本傳輸安…

相關文章
相關標籤/搜索