淺談Charles抓包原理

類似Charles這樣的抓包工具只怎,對于高效程序員是必不可少的袜瞬;
本文不會介紹Charles的安裝及使用,主要是淺顯的探討其抓包原理身堡;Charles的安裝及使用相關(guān)內(nèi)容可以參考以下文章:

iOS開發(fā)輔助工具-抓包工具-Charles青花瓷
Charles 4.5.6 Mac pojie版

大致原理

Charles作為一個中間人代理邓尤,在客戶端給服務器端發(fā)消息的時候,會截取客戶端發(fā)送給服務器的請求贴谎,然后偽裝成客戶端與服務器進行通信汞扎;服務器返回數(shù)據(jù)時將截取的數(shù)據(jù)發(fā)送給客戶端,偽裝成服務器與客戶端進行通信擅这。

這個過程其實很簡單澈魄,但不同于HTTP,更安全的HTTPS能有效防止中間人攻擊蕾哟;Charles是如何截取HTTPS鏈接的呢一忱?

HTTPS的安全性

相比HTTP,HTTPS之所以更安全的是因為其在HTTP傳輸層之上加了一個安全層(SSL或TLS協(xié)議)谭确;HTTPS的安全性主要體現(xiàn)在下面3個方面:

  • 數(shù)據(jù)的保密性(防竊聽)
  • 數(shù)據(jù)的完整性(防篡改)
  • 通信雙方身份的真實性(防冒充)
數(shù)據(jù)的保密性

要實現(xiàn)數(shù)據(jù)的保密帘营,就需要使用加密算法對數(shù)據(jù)進行加密;加密算法大致分為兩類:對稱加密逐哈,非對稱加密芬迄;

  • 對稱加密:加密和解密使用相同密鑰的加密算法。對稱加密速度快昂秃,通常在需要加密大量數(shù)據(jù)時使用禀梳;因為加密和解密都使用同一個密鑰,把密鑰傳遞到解密者的過程中也會有風險肠骆,因此對稱加密不是很安全的算途;常用的對稱加密算法有:DES、3DES蚀腿、RC2嘴瓤、RC4、RC5莉钙、IDEA等

  • 非對稱加密廓脆,加密和解密使用不同密鑰的加密算法;它使用了一對密鑰磁玉,公鑰私鑰停忿;使用公鑰加密的數(shù)據(jù),利用私鑰解密蚊伞;使用私鑰加密的數(shù)據(jù)席赂,利用公鑰解密吮铭;非對稱加密通常使用RSA算法(RSA原理探究),RSA的公鑰和私鑰其實就是一組數(shù)字氧枣,數(shù)字長度越長加密強度越大沐兵;數(shù)字一般是高于768位(二進制),不能被輕易破解便监;RSA算法加密解密其實就是對這個比較大的數(shù)進行運算;因此RSA非對稱加密要比對稱加密慢很多碳想,為了保證效率烧董,RSA非對稱加密只用于小數(shù)據(jù);

基于對稱加密和非對稱加密的優(yōu)缺點胧奔,HTTPS的加密方案就是:

連接建立過程(TLS握手):
  1. 客戶端向服務器請求(發(fā)送TLS版本號逊移、支持的加密算法、隨機數(shù)Client Random)龙填;
  2. 服務器返回非對稱加密的公鑰(證書)胳泉、商定的加密算法、隨機數(shù)Server Random給客戶端岩遗;
  3. 客戶端驗證服務器返回的證書扇商;
  4. 證書驗證通過,客戶端就會生成一個新的隨機數(shù)pre-master宿礁,用服務器的公鑰加密該隨機數(shù)并發(fā)送給服務器案铺;服務器收到后,用私鑰解密梆靖,得到客戶端發(fā)來的隨機數(shù)pre-master控汉。
    至此,客戶端和服務端雙方都共享了三個隨機數(shù)返吻,分別是Client Random/Server Random/pre-master姑子。客戶端就根據(jù)服務器返回的證書及3個隨機數(shù)生成一個會話密鑰(對稱加密)测僵;
  5. 客戶端用服務器返回的公鑰(證書)對會話密鑰進行非對稱加密后傳輸給服務器街佑;
  6. 服務器通過私鑰解密得到會話密鑰;
  7. 客戶端和服務器互相傳輸加密的握手消息來驗證安全通道是否已完成恨课;
通信過程
  1. 客戶端使用會話密鑰對傳輸?shù)臄?shù)據(jù)進行對稱加密傳輸給服務器舆乔;
  2. 服務器使用會話密鑰對傳輸?shù)臄?shù)據(jù)進行解密;
  3. 服務器使用會話密鑰對響應的數(shù)據(jù)進行對稱加密傳輸給客戶端剂公;
  4. 客戶端使用會話密鑰對傳輸?shù)臄?shù)據(jù)進行解密希俩;

總的來說就是:連接建立過程使用非對稱加密,后續(xù)通信過程使用對稱加密纲辽;

數(shù)據(jù)的完整性

數(shù)據(jù)的加密颜武,有效保證了數(shù)據(jù)不被竊聽(很難得到原始的數(shù)據(jù))璃搜,但傳輸?shù)臄?shù)據(jù)在傳輸過程中有可能被篡改或替換;比如:
傳輸?shù)脑紨?shù)據(jù)是123456鳞上,經(jīng)過加密后數(shù)據(jù)是abcdef这吻;客戶端將abcdef這個數(shù)據(jù)傳輸給服務器,傳輸過程中中間人能拿到abcdef這個數(shù)據(jù)篙议,但因為沒有密鑰很難解密出原始數(shù)據(jù)123456唾糯;但是,中間人還是能對得到的abcdef這個加密數(shù)據(jù)進行處理鬼贱,比如將這個數(shù)據(jù)改為xxxxx移怯;這樣服務器得到的數(shù)據(jù)就是被篡改后的xxxxx;同樣这难,服務器返回數(shù)據(jù)給客戶端時也會被篡改舟误;這樣其實也是不安全的;
解決方案是進行數(shù)字簽名:使用Hash算法將任意長度的字符串轉(zhuǎn)化為固定長度的字符串姻乓,該過程不可逆嵌溢,可用來作數(shù)據(jù)完整性校驗;
具體可參考淺談Hash
數(shù)字簽名的簡要過程(服務器-->客戶端為例蹋岩,客戶端-->服務器類似):

  1. 服務器使用Hash算法對數(shù)據(jù)提取定長摘要
  2. 服務器使用私鑰對摘要進行加密赖草,作為數(shù)字簽名
  3. 服務器將數(shù)字簽名連同加密的數(shù)據(jù)一同傳輸給客戶端
  4. 客戶端使用公鑰對數(shù)字簽名進行解密,得到摘要A
  5. 客戶端對解密后的傳輸數(shù)據(jù)也使用Hash算法得到定長摘要B
  6. 對比摘要A和摘要B星澳,如果不一致則數(shù)據(jù)已被篡改
通信雙方身份的真實性

以上加密過程疚顷,最核心的就是非對稱加密的公鑰和私鑰如暖;如果這個密鑰都是攻擊者提供的,那傳輸?shù)臄?shù)據(jù)在攻擊者那里也是相當于裸露的;如何確保密鑰是不被冒充的呢?HTTPS使用了數(shù)字證書(簽名)雹锣,數(shù)字證書就是身份認證機構(gòu)CA(Certificate Authority)加在數(shù)字身份證上的一個簽名,證書的合法性可以向CA驗證;證書的制作方法是公開的寇窑,任何人都可以自己制作證書先慷,但只有權(quán)威的證書頒發(fā)機構(gòu)的證書能通過CA認證;
數(shù)字證書主要包含以下信息:

  • 證書頒發(fā)機構(gòu)
  • 證書頒發(fā)機構(gòu)簽名
  • 證書版本祝谚、有效期
  • 證書綁定的服務器域名
  • 簽名使用的加密算法(非對稱算法,如RSA)
  • 公鑰

數(shù)字證書的作用意荤,是用來認證公鑰持有者的身份炬藤,以防止第三方進行冒充;簡單說就珠,證書就是用來告訴客戶端寇壳,服務端是否合法。
為了讓服務端的公鑰被信任妻怎,服務端的證書都由CA簽名壳炎,CA就是網(wǎng)絡(luò)世界里的公安局,具有極高的可信度逼侦,所以由它來給各個公鑰簽名匿辩,信任的一方簽發(fā)的證書,那必然證書也是被信任的榛丢。

數(shù)字證書簽發(fā)和驗證流程

  • CA簽發(fā)證書的過程

首先CA會把持有者的公鑰铲球、頒發(fā)者、用途晰赞、有效時間等信息打包稼病;然后對這些信息進行Hash計算。然后CA會使用自己的私鑰將該Hash值加密掖鱼,生成Certificate Signature然走,即CA對證書做了簽名。最后將Certificate Signature添加在文件證書上锨用,形成了數(shù)字證書丰刊;

  • 客戶端校驗服務端的數(shù)字證書的過程:

客戶端會使用同樣的Hash算法獲取該證書的Hash值A(chǔ);
通常瀏覽器和操作系統(tǒng)中集成了CA的公鑰信息增拥,瀏覽器收到證書后可以使用CA的公鑰解密Certificate Signature內(nèi)容啄巧,得到一個Hash值B;
最后比較A和B,如果值相同掌栅,則為可信賴的證書秩仆,否則認為證書不可信。

客戶端和服務器連接過程中猾封,收到服務器返回的證書后澄耍,會先向CA驗證證書的合法性(根據(jù)證書的簽名、綁定的域名等信息),如果校驗不通過中止連接齐莲,并提示證書不安全痢站。

HTTPS抓包原理

<unknown>的原因

首先我們看下默認情況下帽芽,使用Charles抓包HTTPS的情況:

正常情況下冻押,得到的結(jié)果都是<unknown>客冈;這是因為我們前面講的HTTPS的安全性的作用姜胖;
點擊<unknown>查看具體信息:

tls

(ps: 截圖中也可以看到 TLS版本號,協(xié)商的加密算法等信息啤覆;這個和上述流程對應上了)

可以看到帐要,報錯原因是SSL握手失敗怠李,也就是在TLS/SSL連接建立時就已經(jīng)失敗殿衰,還沒有到數(shù)據(jù)通信這步來朱庆;
進一步查看TLS Alert Code得到更詳細的信息:

handshake_failure (40) - Unable to negotiate an acceptable set of security parameters, this probably means there are no cipher suites in common

大概意思是,密鑰參數(shù)沒有協(xié)商一致闷祥;
這是因為Charles為了能竊聽娱颊、篡改HTTPS通信數(shù)據(jù),在客戶端與服務端連接建立過程中(參考上面HTTPS連接建立過程的第2步)凯砍,當服務器返回非對稱加密的公鑰(證書)维蒙、商定的加密算法、隨機數(shù)Server Random給客戶端時果覆,Charles攔截到服務器返回給客戶端的公鑰(證書)替換成自己的公鑰(證書)再發(fā)送給客戶端; 準備以此來冒充通信的雙方殖熟;
但是前面我們也分析過了局待,HTTPS會通過數(shù)字證書驗證通信雙方身份的真實性;Charles的證書并不能通過CA驗證菱属,證書未驗證通過那客戶端后續(xù)流程就不會進行:包括生成一個新的隨機數(shù)pre-master钳榨、生成非對稱密鑰等流程;最終導致連接失斉γ拧薛耻;

由于是TLS握手都沒成功,不止是Charles失敗赏陵,原先的客戶端和服務器也不能建立正常連接饼齿,客戶端網(wǎng)絡(luò)請求也都是失敗蝙搔;

Charles的策略

Charles如何解決證書驗證的問題呢缕溉?
根據(jù)官方教程,需要我們使用者在手機上安裝Charles根證書并設(shè)置為信任:

配置好后吃型,就能和HTTP一樣抓包使用了证鸥;
為什么手機安裝了Charles根證書后就能正常抓包呢?結(jié)合數(shù)字證書驗證的原理,CA起到了決定性作用枉层;一般常用的CA證書(公鑰)是事先內(nèi)嵌在手機系統(tǒng)里的泉褐,如果不是內(nèi)嵌的CA私鑰簽名的都驗證不通過;Charles根證書就類似Charles CA鸟蜡,用戶手動安裝到系統(tǒng)并設(shè)置信任膜赃,相當于系統(tǒng)里多了一個CA;后續(xù)Charles的weizao的經(jīng)過Charles根證書(私鑰)簽名的公鑰就能驗證通過矩欠,握手成功财剖,通信過程也能竊聽、篡改癌淮;

Charles抓包的完整流程
  • 當客戶端和服務器建立連接時躺坟,Charles會攔截到服務器返回的證書(服務器公鑰)
  • 然后動態(tài)生成一張weizao證書(Charles公鑰/假公鑰)發(fā)送給客戶端
  • 客戶端收到Charles證書后,進行驗證乳蓄;因為之前我們手機設(shè)置了信任咪橙,所以驗證通過;(只要手機不信任這種證書虚倒,HTTPS還是能確保安全的)
  • 客戶端生成會話密鑰美侦,使用Charles證書對會話密鑰進行加密再傳輸給服務器
  • Charles攔截到客戶端傳輸?shù)臄?shù)據(jù),使用自己的Charles私鑰進行解密得到會話密鑰
  • 連接成功后魂奥,客戶端和服務器通信菠剩,客戶端對傳輸?shù)臄?shù)據(jù)使用會話密鑰加密并使用公鑰對數(shù)據(jù)摘要進行數(shù)字簽名,一同傳輸給服務器耻煤;
  • Charles攔截到通信的數(shù)據(jù)具壮,使用之前獲得的會話密鑰解密就能得到原始數(shù)據(jù);
  • Charles同樣也能篡改通信的數(shù)據(jù):將篡改后的數(shù)據(jù)重新加密并重新生成摘要并使用之前獲得的公鑰進行數(shù)字簽名哈蝇,替換原本的簽名棺妓,再傳輸給服務器;
  • 服務器收取到數(shù)據(jù)炮赦,按正常流程解密驗證怜跑;
  • 服務器返回響應數(shù)據(jù)時,Charles也是類似攔截過程

整個流程大致如下圖:

防抓包

從上文可以知道吠勘,抓包主要的原理就是中間人替換了原本的證書性芬;防抓包就可以通過針對證書的校驗來實現(xiàn);
AFN有封裝類似校驗證書的功能剧防,接下來主要介紹AFN+SSL Pinning的方式對證書進行校驗批旺;

  • 獲取服務器的HTTPS證書,并把證書加到項目Bundle中;
  • AFN代碼設(shè)置Policy
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode: AFSSLPinningModeCertificate];
securityPolicy.allowInvalidCertificates = YES;
securityPolicy.validatesDomainName = NO;
[AFHTTPSessionManager manager].securityPolicy = securityPolicy;
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode: AFSSLPinningModeCertificate];

這句代碼中诵姜,會去Bundle中獲取所有的cer證書文件:

代碼

AFSSLPinningMode有3種模式:

// 驗證證書的模式
typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
    AFSSLPinningModeNone, // 不做驗證:證書是信任機構(gòu)簽發(fā)的就會通過汽煮,若是自己服務器生成的證書搏熄,不會通過
    AFSSLPinningModeCertificate, // 證書驗證:驗證證書的域名/有效期等信息,對比服務端返回的證書和客戶端返回的是否一致
    AFSSLPinningModePublicKey, // 公鑰驗證(只驗證證書里的公鑰暇赤,不驗證證書的有效期等信息)
};

在證書配置好及代碼設(shè)置好后心例,再使用抓包軟件就無法查看更改接口了;

AFN的HTTPS校驗核心代碼在evaluateServerTrust方法內(nèi)

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
                  forDomain:(NSString *)domain {
    if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) {
        NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");
        return NO;
    }

    NSMutableArray *policies = [NSMutableArray array];
    if (self.validatesDomainName) {
        // 驗證域名時鞋囊,返回用于評估SSL證書鏈的策略對象止后。
        [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
    } else {
        // Returns a policy object for the default X.509 policy.
        [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
    }

    // 設(shè)置驗證策略
    SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);

    if (self.SSLPinningMode == AFSSLPinningModeNone) {
         // 如果支持自簽名則驗證通過 否則驗證serverTrust是否有效、有效則驗證通過
        // SSLPinningMode=AFSSLPinningModeNone allowInvalidCertificates=YES 表示任何證書都能驗證通過
        // AFServerTrustIsValid(serverTrust) 證書是否是系統(tǒng)信任的證書
        return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
    } else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
        return NO;
    }

    switch (self.SSLPinningMode) {
        case AFSSLPinningModeNone:
        default:
            return NO;
        case AFSSLPinningModeCertificate: {
            NSMutableArray *pinnedCertificates = [NSMutableArray array];
            for (NSData *certificateData in self.pinnedCertificates) {
                [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
            }
            // 設(shè)置了參與校驗錨點證書之后溜腐,假如驗證的數(shù)字證書是這個錨點證書的子節(jié)點译株,即驗證的數(shù)字證書是由錨點證書對應CA或子CA簽發(fā)的,或是該證書本身挺益,則信任該證書
            SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);

            if (!AFServerTrustIsValid(serverTrust)) {
                return NO;
            }

            // obtain the chain after being validated, which *should* contain the pinned certificate in the last position (if it's the Root CA)
            // 服務器證書和客戶端的是否相同歉糜,如果有一個相同則通過
            NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
            
            for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
                if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
                    return YES;
                }
            }
            
            return NO;
        }
        case AFSSLPinningModePublicKey: {
            // 比較證書當中公鑰(PublicKey)部分來進行驗證,通過SecTrustCopyPublicKey方法獲取本地證書和服務器證書望众,然后進行比較匪补,如果有一個相同,則通過
            NSUInteger trustedPublicKeyCount = 0;
            NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);

            for (id trustChainPublicKey in publicKeys) {
                for (id pinnedPublicKey in self.pinnedPublicKeys) {
                    if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) {
                        trustedPublicKeyCount += 1;
                    }
                }
            }
            return trustedPublicKeyCount > 0;
        }
    }
    
    return NO;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末烂翰,一起剝皮案震驚了整個濱河市夯缺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌甘耿,老刑警劉巖踊兜,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異佳恬,居然都是意外死亡润文,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門殿怜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人曙砂,你說我怎么就攤上這事头谜。” “怎么了鸠澈?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵柱告,是天一觀的道長。 經(jīng)常有香客問我笑陈,道長际度,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任涵妥,我火速辦了婚禮乖菱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己窒所,他們只是感情好鹉勒,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著吵取,像睡著了一般禽额。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上皮官,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天脯倒,我揣著相機與錄音,去河邊找鬼捺氢。 笑死藻丢,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的讯沈。 我是一名探鬼主播郁岩,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼缺狠!你這毒婦竟也來了问慎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤挤茄,失蹤者是張志新(化名)和其女友劉穎如叼,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體穷劈,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡笼恰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了歇终。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片社证。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖评凝,靈堂內(nèi)的尸體忽然破棺而出追葡,到底是詐尸還是另有隱情,我是刑警寧澤奕短,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布宜肉,位于F島的核電站,受9級特大地震影響翎碑,放射性物質(zhì)發(fā)生泄漏谬返。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一日杈、第九天 我趴在偏房一處隱蔽的房頂上張望遣铝。 院中可真熱鬧佑刷,春花似錦、人聲如沸翰蠢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽梁沧。三九已至檀何,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間廷支,已是汗流浹背频鉴。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留恋拍,地道東北人垛孔。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像施敢,于是被迫代替她去往敵國和親周荐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容