原文來(lái)自烏云
隨著安全的普及,https通信應(yīng)用越發(fā)廣泛浪听,但是由于對(duì)https不熟悉導(dǎo)致開(kāi)發(fā)人員頻繁錯(cuò)誤的使用https吃嘿,例如最常見(jiàn)的是未校驗(yàn)https證書(shū)從而導(dǎo)致“中間人攻擊”们镜,并且由于修復(fù)方案也一直是個(gè)坑,導(dǎo)致修復(fù)這個(gè)問(wèn)題時(shí)踩各種坑的妖,故謹(jǐn)以此文簡(jiǎn)單的介紹相關(guān)問(wèn)題。
一足陨、前言
本文第一節(jié)主要講述https的握手過(guò)程嫂粟,第二節(jié)主要講述常見(jiàn)的“https中間人攻擊”場(chǎng)景,第三節(jié)主要介紹證書(shū)校驗(yàn)修復(fù)方案墨缘,各位看官可根據(jù)自己口味瀏覽星虹。
二、HTTPS握手過(guò)程
首先來(lái)看下https的工作原理镊讼,上圖大致介紹了https的握手流程宽涌,后續(xù)我們通過(guò)抓包看下每個(gè)握手包到底干了些什么神奇的事。
注:本文所有內(nèi)容以TLS_RSA_WITH_AES_128_CBC_SHA加密組件作為基礎(chǔ)進(jìn)行說(shuō)明蝶棋,其他加密組件以及TLS版本會(huì)存在一定差異卸亮,例如TLS1. 3 針對(duì)移動(dòng)客戶(hù)端有了很大的改動(dòng),現(xiàn)在的ECDHE等密鑰交換算法與RSA作為密鑰交換算法也完全不一樣嚼松,所以有些地方和大家實(shí)際操作會(huì)存在一定出入嫡良。
1.TCP三次握手
我訪問(wèn)的支付寶的官網(wǎng)www.alipay.com抓取的數(shù)據(jù)锰扶。
2.Client Hello
TLS的版本號(hào)和隨機(jī)數(shù)random_c:這個(gè)是用來(lái)生成最后加密密鑰的因子之一献酗,它包含兩部分,時(shí)間戳和隨機(jī)數(shù) session-id:用來(lái)標(biāo)識(shí)會(huì)話坷牛,第一次握手時(shí)為空罕偎,如果以前建立過(guò),可以直接帶過(guò)去從而避免完全握手 Cipher Suites加密組件列表:瀏覽器所支持的加密算法的清單客戶(hù)端支持的加密簽名算法的列表京闰,讓服務(wù)器進(jìn)行選擇 擴(kuò)展字段:比如密碼交換算法的參數(shù)颜及、請(qǐng)求主機(jī)的名字,用于單ip多域名的情況指定域名蹂楣。
3.Sever Hello
隨機(jī)數(shù)rando_s俏站,這個(gè)是用來(lái)生成最后加密密鑰的因子之一,包含兩部分痊土,時(shí)間戳和隨機(jī)數(shù) 32 字節(jié)的SID肄扎,在我們想要重新連接到該站點(diǎn)的時(shí)候可以避免一整套握手過(guò)程。 在客戶(hù)端提供的加密組件中赁酝,服務(wù)器選擇了TLS_RSA_WITH_AES_128_CBC_SHA組件犯祠。
4.Certificate
證書(shū)是https里非常重要的主體,可用來(lái)識(shí)別對(duì)方是否可信酌呆,以及用其公鑰做密鑰交換衡载。可以看見(jiàn)證書(shū)里面包含證書(shū)的頒發(fā)者隙袁,證書(shū)的使用者痰娱,證書(shū)的公鑰弃榨,頒發(fā)者的簽名等信息。其中Issuer Name是簽發(fā)此證書(shū)的CA名稱(chēng)梨睁,用來(lái)指定簽發(fā)證書(shū)的CA的可識(shí)別的唯一名稱(chēng)(DN惭墓, Distinguished Name),用于證書(shū)鏈的認(rèn)證而姐,這樣通過(guò)各級(jí)實(shí)體證書(shū)的驗(yàn)證腊凶,逐漸上溯到鏈的終止點(diǎn),即可信任的根CA拴念,如果到達(dá)終點(diǎn)在自己的信任列表內(nèi)未發(fā)現(xiàn)可信任的CA則認(rèn)為此證書(shū)不可信钧萍。
驗(yàn)證證書(shū)鏈的時(shí)候,用上一級(jí)的公鑰對(duì)證書(shū)里的簽名進(jìn)行解密政鼠,還原對(duì)應(yīng)的摘要值风瘦,再使用證書(shū)信息計(jì)算證書(shū)的摘要值,最后通過(guò)對(duì)比兩個(gè)摘要值是否相等公般,如果不相等則認(rèn)為該證書(shū)不可信万搔,如果相等則認(rèn)為該級(jí)證書(shū)鏈正確,以此類(lèi)推對(duì)整個(gè)證書(shū)鏈進(jìn)行校驗(yàn)官帘。
二級(jí)機(jī)構(gòu)的證書(shū)瞬雹。
三、中間人攻擊
https握手過(guò)程的證書(shū)校驗(yàn)環(huán)節(jié)就是為了識(shí)別證書(shū)的有效性唯一性等等刽虹,所以嚴(yán)格意義上來(lái)說(shuō)https下不存在中間人攻擊酗捌,存在中間人攻擊的前提條件是沒(méi)有嚴(yán)格的對(duì)證書(shū)進(jìn)行校驗(yàn),或者人為的信任偽造證書(shū)涌哲,下面一起看下幾種常見(jiàn)的https“中間人攻擊”場(chǎng)景胖缤。
1.證書(shū)未校驗(yàn)
由于客戶(hù)端沒(méi)有做任何的證書(shū)校驗(yàn),所以此時(shí)隨意一張證書(shū)都可以進(jìn)行中間人攻擊阀圾,可以使用burp里的這個(gè)模塊進(jìn)行中間人攻擊哪廓。
通過(guò)瀏覽器查看實(shí)際的https證書(shū),是一個(gè)自簽名的偽造證書(shū)初烘。
2.部分校驗(yàn)
做了部分校驗(yàn)涡真,例如在證書(shū)校驗(yàn)過(guò)程中只做了證書(shū)域名是否匹配的校驗(yàn),可以使用burp的如下模塊生成任意域名的偽造證書(shū)進(jìn)行中間人攻擊账月。
實(shí)際生成的證書(shū)效果综膀,如果只做了域名、證書(shū)是否過(guò)期等校驗(yàn)可輕松進(jìn)行中間人攻擊(由于chrome是做了證書(shū)校驗(yàn)的所以會(huì)提示證書(shū)不可信任)局齿。
3.證書(shū)鏈校驗(yàn)
如果客戶(hù)端對(duì)證書(shū)鏈做了校驗(yàn)剧劝,那么攻擊難度就會(huì)上升一個(gè)層次,此時(shí)需要人為的信任偽造的證書(shū)或者安裝偽造的CA公鑰證書(shū)從而間接信任偽造的證書(shū)抓歼,可以使用burp的如下模塊進(jìn)行中間人攻擊讥此。
4.手機(jī)客戶(hù)端Https數(shù)據(jù)包抓取
上述第一拢锹、二種情況不多加贅述,第三種情況就是我們經(jīng)常使用的抓手機(jī)應(yīng)用https數(shù)據(jù)包的方法萄喳,即導(dǎo)入代理工具的公鑰證書(shū)到手機(jī)里卒稳,再進(jìn)行https數(shù)據(jù)包的抓取。導(dǎo)入手機(jī)的公鑰證書(shū)在android平臺(tái)上稱(chēng)之為受信任的憑據(jù)他巨,在ios平臺(tái)上稱(chēng)之為描述文件充坑,可以通過(guò)openssl的命令直接查看我們導(dǎo)入到手機(jī)客戶(hù)端里的這個(gè)PortSwiggerCA.crt。
可以看見(jiàn)是Issuer和Subject一樣的自簽名CA公鑰證書(shū)染突,另外我們也可以通過(guò)證書(shū)類(lèi)型就可以知道此為公鑰證書(shū)捻爷,crt、der格式的證書(shū)不支持存儲(chǔ)私鑰或證書(shū)路徑(有興趣的同學(xué)可查找證書(shū)相關(guān)信息)份企。導(dǎo)入CA公鑰證書(shū)之后也榄,參考上文的證書(shū)校驗(yàn)過(guò)程不難發(fā)現(xiàn)通過(guò)此方式能通過(guò)證書(shū)鏈校驗(yàn),從而形成中間人攻擊司志,客戶(hù)端使用代理工具的公鑰證書(shū)加密隨機(jī)數(shù)甜紫,代理工具使用私鑰解密并計(jì)算得到對(duì)稱(chēng)加密密鑰,再對(duì)數(shù)據(jù)包進(jìn)行解密即可抓取明文數(shù)據(jù)包骂远。
5.中間人攻擊原理
一直在說(shuō)中間人攻擊囚霸,那么中間人攻擊到底是怎么進(jìn)行的呢,下面我們通過(guò)一個(gè)流行的MITM開(kāi)源庫(kù)mitmproxy來(lái)分析中間人攻擊的原理吧史。中間人攻擊的關(guān)鍵在于https握手過(guò)程的ClientKeyExchange邮辽,由于pre key交換的時(shí)候是使用服務(wù)器證書(shū)里的公鑰進(jìn)行加密,如果用的偽造證書(shū)的公鑰贸营,那么中間人就可以解開(kāi)該密文得到pre_master_secret計(jì)算出用于對(duì)稱(chēng)加密算法的master_key,從而獲取到客戶(hù)端發(fā)送的數(shù)據(jù);然后中間人代理工具再使用其和服務(wù)端的master_key加密傳輸給服務(wù)端;同樣的服務(wù)器返回給客戶(hù)端的數(shù)據(jù)也是經(jīng)過(guò)中間人解密再加密岩睁,于是完整的https中間人攻擊過(guò)程就形成了钞脂,一圖勝千言,來(lái)吧捕儒。
通過(guò)讀Mitmproxy的源碼發(fā)現(xiàn)mitmproxy生成偽造證書(shū)的函數(shù)如下:
通過(guò)上述函數(shù)一張完美偽造的證書(shū)就出現(xiàn)了冰啃,使用瀏覽器通過(guò)mitmproxy做代理看下實(shí)際偽造出來(lái)的證書(shū)。
可以看到實(shí)際的證書(shū)是由mimtproxy頒發(fā)的刘莹,其中的公鑰就是mimtproxy自己的公鑰阎毅,后續(xù)的加密數(shù)據(jù)就可以使用mimtproxy的私鑰進(jìn)行解密了。如果導(dǎo)入了mitmproxy的公鑰證書(shū)到客戶(hù)端点弯,那么該偽造的證書(shū)就可以完美的通過(guò)客戶(hù)端的證書(shū)校驗(yàn)了扇调。這就是平時(shí)為什么導(dǎo)入代理的CA證書(shū)到手機(jī)客戶(hù)端能抓取https的原因。
四抢肛、證書(shū)校驗(yàn)
通過(guò)上文第一和第二部分的說(shuō)明狼钮,相信大家已經(jīng)對(duì)https有個(gè)大概的了解了碳柱,那么問(wèn)題來(lái)了,怎樣才能防止這些“中間人攻擊”呢?
app證書(shū)校驗(yàn)已經(jīng)是一個(gè)老生常談的問(wèn)題了熬芜,但是市場(chǎng)上還是有很多的app未做好證書(shū)校驗(yàn)莲镣,有些只做了部分校驗(yàn),例如檢查證書(shū)域名是否匹配證書(shū)是否過(guò)期涎拉,更多數(shù)的是根本就不做校驗(yàn)瑞侮,于是就造成了中間人攻擊。做證書(shū)校驗(yàn)需要做完全鼓拧,只做一部分都會(huì)導(dǎo)致中間人攻擊区岗,對(duì)于安全要求并不是特別高的app可使用如下校驗(yàn)方式:
查看證書(shū)是否過(guò)期
服務(wù)器證書(shū)上的域名是否和服務(wù)器的實(shí)際域名相匹配
校驗(yàn)證書(shū)鏈
可參考 http://drops.wooyun.org/tips/3296 此類(lèi)校驗(yàn)方式雖然在導(dǎo)入CA公鑰證書(shū)到客戶(hù)端之后會(huì)造成中間人攻擊,但是攻擊門(mén)檻已相對(duì)較高毁枯,所以對(duì)于安全要求不是特別高的app可采用此方法進(jìn)行防御慈缔。對(duì)于安全有較高要求一些app(例如金融)上述方法或許還未達(dá)到要求,那么此時(shí)可以使用如下更安全的校驗(yàn)方式种玛,將服務(wù)端證書(shū)打包放到app里藐鹤,再建立https鏈接時(shí)使用本地證書(shū)和網(wǎng)絡(luò)下發(fā)證書(shū)進(jìn)行一致性校驗(yàn)。
此類(lèi)校驗(yàn)即便導(dǎo)入CA公鑰證書(shū)也無(wú)法進(jìn)行中間人攻擊赂韵,但是相應(yīng)的維護(hù)成本會(huì)相對(duì)升高娱节,例如服務(wù)器證書(shū)過(guò)期,證書(shū)更換時(shí)如果app不升級(jí)就無(wú)法使用祭示,那么可以改一下肄满,生成一對(duì)RSA的公私鑰,公鑰可硬編碼在app质涛,私鑰放服務(wù)器稠歉。 https握手前可通過(guò)服務(wù)器下發(fā)證書(shū)信息,例如公鑰汇陆、辦法機(jī)構(gòu)怒炸、簽名等,該下發(fā)的信息使用服務(wù)器里的私鑰進(jìn)行簽名; 通過(guò)app里預(yù)置的公鑰驗(yàn)簽得到證書(shū)信息并存在內(nèi)容中供后續(xù)使用; 發(fā)起https連接獲取服務(wù)器的證書(shū)毡代,通過(guò)對(duì)比兩個(gè)證書(shū)信息是否一致進(jìn)行證書(shū)校驗(yàn)阅羹。
這樣即可避免強(qiáng)升的問(wèn)題,但是問(wèn)題又來(lái)了教寂,這樣效率是不是低太多了?答案是肯定的捏鱼,所以對(duì)于安全要求一般的應(yīng)用使用第一種方法即可,對(duì)于一些安全要求較高的例如金融企業(yè)可選擇第二種方法酪耕。
說(shuō)了挺多导梆,但是該來(lái)的問(wèn)題還是會(huì)來(lái)啊!現(xiàn)在的app一般采用混合開(kāi)發(fā),會(huì)使用很多webveiw直接加載html 5 頁(yè)面,上面的方法只解決了java層證書(shū)校驗(yàn)的問(wèn)題问潭,并沒(méi)有涉及到webview里面的證書(shū)校驗(yàn)猿诸,對(duì)于這種情況怎么辦呢?既然問(wèn)題來(lái)了那么就一起說(shuō)說(shuō)解決方案,對(duì)于webview加載html 5 進(jìn)行證書(shū)校驗(yàn)的方法如下:
webview創(chuàng)建實(shí)例加載網(wǎng)頁(yè)時(shí)通過(guò)onPageStart方法返回url地址; 將返回的地址轉(zhuǎn)發(fā)到j(luò)ava層使用上述的證書(shū)校驗(yàn)代碼進(jìn)行進(jìn)行校驗(yàn); 如果證書(shū)校驗(yàn)出錯(cuò)則使用stoploading()方法停止網(wǎng)頁(yè)加載狡忙,證書(shū)校驗(yàn)通過(guò)則正常加載梳虽。
支付寶官網(wǎng)簽名證書(shū)。
不僅僅進(jìn)行證書(shū)鏈的校驗(yàn)灾茁,此時(shí)還會(huì)進(jìn)行另一個(gè)協(xié)議即Online Certificate Status Protocol窜觉, 該協(xié)議為證書(shū)狀態(tài)在線查詢(xún)協(xié)議,一個(gè)實(shí)時(shí)查詢(xún)證書(shū)是否吊銷(xiāo)的方式北专,客戶(hù)端發(fā)送證書(shū)的信息并請(qǐng)求查詢(xún)禀挫,服務(wù)器返回正常、吊銷(xiāo)或未知中的任何一個(gè)狀態(tài)拓颓,這個(gè)查詢(xún)地址會(huì)附在證書(shū)中供客戶(hù)端使用语婴。
5.Server Hello Done
這是一個(gè)零字節(jié)信息,用于告訴客戶(hù)端整個(gè)server hello過(guò)程已經(jīng)結(jié)束驶睦。
6.ClientKeyExchange
客戶(hù)端在驗(yàn)證證書(shū)有效之后發(fā)送ClientKeyExchange消息砰左,ClientKeyExchange消息中,會(huì)設(shè)置 48 字節(jié)的premaster secret(因?yàn)榈腡LS版本的原因场航,這里沒(méi)有顯示premaster)缠导,通過(guò)密鑰交換算法加密發(fā)送premaster secret的值,例如通過(guò) RSA公鑰加密premaster secret的得到Encrypted PreMaster傳給服務(wù)端溉痢。PreMaster前兩個(gè)字節(jié)是TLS的版本號(hào)僻造,該版本號(hào)字段是用來(lái)防止版本回退攻擊的。
從握手包到目前為止孩饼,已經(jīng)出現(xiàn)了三個(gè)隨機(jī)數(shù)(客戶(hù)端的random_c髓削,服務(wù)端的random_s,premaster secret)捣辆,使用這三個(gè)隨機(jī)數(shù)以及一定的算法即可獲得對(duì)稱(chēng)加密AES的加密主密鑰Master-key蔬螟,主密鑰的生成非常的精妙。
7.Change Cipher Spec
發(fā)送一個(gè)不加密的信息汽畴,瀏覽器使用該信息通知服務(wù)器后續(xù)的通信都采用協(xié)商的通信密鑰和加密算法進(jìn)行加密通信。
8.Encrypted Handshake Message
驗(yàn)證加密算法的有效性耸序,結(jié)合之前所有通信參數(shù)的 hash 值與其它相關(guān)信息生成一段數(shù)據(jù)忍些,采用協(xié)商密鑰 session secret 與算法進(jìn)行加密,然后發(fā)送給服務(wù)器用于數(shù)據(jù)與握手驗(yàn)證坎怪,通過(guò)驗(yàn)證說(shuō)明加密算法有效罢坝。
9.Change_cipher_spec
Encrypted Handshake Message通過(guò)驗(yàn)證之后,服務(wù)器同樣發(fā)送 change_cipher_spec 以通知客戶(hù)端后續(xù)的通信都采用協(xié)商的密鑰與算法進(jìn)行加密通信。
10.Encrypted Handshake Message
同樣的嘁酿,服務(wù)端也會(huì)發(fā)送一個(gè)Encrypted Handshake Message供客戶(hù)端驗(yàn)證加密算法有效性隙券。
11.Application Data
經(jīng)過(guò)一大串的的計(jì)算之后,終于一切就緒闹司,后續(xù)傳輸?shù)臄?shù)據(jù)可通過(guò)主密鑰master key進(jìn)行加密傳輸娱仔,加密數(shù)據(jù)查看圖中的Encrypted Apploication Data字段數(shù)據(jù),至此https的一次完整握手以及數(shù)據(jù)加密傳輸終于完成游桩。
https里還有很多可優(yōu)化并且很多精妙的設(shè)計(jì)牲迫,例如為了防止經(jīng)常進(jìn)行完整的https握手影響性能,于是通過(guò)sessionid來(lái)避免同一個(gè)客戶(hù)端重復(fù)完成握手借卧,但是又由于sessionid消耗的內(nèi)存性能比較大盹憎,于是又出現(xiàn)了new session ticket,如果客戶(hù)端表明它支持Session Ticket并且服務(wù)端也支持铐刘,那么在TLS握手的最后一步服務(wù)器將包含一個(gè)“New Session Ticket”信息陪每,其中包含了一個(gè)加密通信所需要的信息,這些數(shù)據(jù)采用一個(gè)只有服務(wù)器知道的密鑰進(jìn)行加密镰吵。這個(gè)Session Ticket由客戶(hù)端進(jìn)行存儲(chǔ)檩禾,并可以在隨后的一次會(huì)話中添加到 ClientHello消息的SessionTicket擴(kuò)展中。雖然所有的會(huì)話信息都只存儲(chǔ)在客戶(hù)端上捡遍,但是由于密鑰只有服務(wù)器知道锌订,所以Session Ticket仍然是安全的,因此這不僅避免了性能消耗還保證了會(huì)話的安全性画株。
最后我們可以使用openssl命令來(lái)直觀的看下https握手的流程: