關(guān)于加密
在解釋SSH、SSL與HTTPS協(xié)議之前我先介紹一下非對(duì)稱加密協(xié)議。在1976年以前,所有的加密都采用對(duì)稱加密,既A使用某種加密規(guī)則對(duì)信息加密,B收到信息后逆向加密規(guī)則解密數(shù)據(jù)。這通信方式產(chǎn)生了一個(gè)難以解決的問題:A如何安全的把加密規(guī)則通知B?
在1976年有兩位數(shù)學(xué)家提出了一個(gè)嶄新的非對(duì)加密的概念:
1.A生成一對(duì)兩把密鑰(公鑰和私鑰)。公鑰是公開的,任何人都可以獲得,私鑰則是保密的。
2.B獲取A生成的公鑰,然后用它對(duì)信息加密。
3.A得到加密后的信息,用私鑰解密。
受這個(gè)思路的啟發(fā),三位數(shù)學(xué)家Rivest、Shamir 和 Adleman 設(shè)計(jì)了一種具體實(shí)現(xiàn)上面描述的非對(duì)稱加密的算法,以他們?nèi)齻€(gè)人的名字命名,就是目前在計(jì)算機(jī)領(lǐng)域應(yīng)用非常廣泛的非對(duì)稱加密算法RSA加密算法。這樣網(wǎng)絡(luò)上傳輸?shù)臄?shù)據(jù)都經(jīng)過公鑰加密,然后用私鑰解密,就算被第三方截獲也無(wú)法解密出原始數(shù)據(jù)。想深入理解非對(duì)稱加密解密的原理可以看這里。
雖然非對(duì)稱加密很安全很強(qiáng)大,但是它也有缺點(diǎn),相對(duì)于對(duì)稱加密它計(jì)算量更大,計(jì)算時(shí)間更長(zhǎng)。所以在大規(guī)模數(shù)據(jù)的安全通信場(chǎng)景中,普遍采用非對(duì)稱加密技術(shù)來交換對(duì)稱加密密鑰,之后的通信都采用對(duì)稱加密技術(shù)加密。
SSH
維基百科中對(duì)SSH協(xié)議的定義如下
Secure Shell(縮寫為SSH),由IETF的網(wǎng)絡(luò)工作小組(Network Working Group)所制定;SSH為一項(xiàng)創(chuàng)建在應(yīng)用層和傳輸層基礎(chǔ)上的安全協(xié)議,為計(jì)算機(jī)上的Shell(殼層)提供安全的傳輸和使用環(huán)境。
傳統(tǒng)的網(wǎng)絡(luò)服務(wù)程序,如rsh、FTP、POP和Telnet其本質(zhì)上都是不安全的;因?yàn)樗鼈冊(cè)诰W(wǎng)絡(luò)上用明文傳送數(shù)據(jù)、用戶帳號(hào)和用戶口令,很容易受到中間人(man-in-the-middle)攻擊方式的攻擊。就是存在另一個(gè)人或者一臺(tái)機(jī)器冒充真正的服務(wù)器接收用戶傳給服務(wù)器的數(shù)據(jù),然后再冒充用戶把數(shù)據(jù)傳給真正的服務(wù)器。
而SSH是目前較可靠,專為遠(yuǎn)程登錄會(huì)話和其他網(wǎng)絡(luò)服務(wù)提供安全性的協(xié)議。利用SSH協(xié)議可以有效防止遠(yuǎn)程管理過程中的信息泄露問題。通過SSH可以對(duì)所有傳輸?shù)臄?shù)據(jù)進(jìn)行加密,也能夠防止DNS欺騙和IP欺騙。
SSH之另一項(xiàng)優(yōu)點(diǎn)為其傳輸?shù)臄?shù)據(jù)可以是經(jīng)過壓縮的,所以可以加快傳輸?shù)乃俣取SH有很多功能,它既可以代替Telnet,又可以為FTP、POP、甚至為PPP提供一個(gè)安全的“通道”。
相信大家看了上面的段定義也是云里霧里。用最通俗的方式來解釋一下SSH。有這么一個(gè)場(chǎng)景:有一個(gè)服務(wù)器在互聯(lián)網(wǎng)的另一頭,你需要遠(yuǎn)程登錄到服務(wù)器來執(zhí)行一些命令配置這臺(tái)服務(wù)器。這個(gè)時(shí)候你和服務(wù)器之間就需要有數(shù)據(jù)通信。假設(shè)客戶端叫A,服務(wù)器叫B。
要實(shí)現(xiàn)通信,最簡(jiǎn)單的想法就是,客戶端服務(wù)器之間建立一個(gè)TCP連接,這樣你的指令就可以通過TCP連接從A傳輸?shù)紹。再仔細(xì)想想,不對(duì),A與B之間需要通信的數(shù)據(jù)中間經(jīng)過了C、D、E、F等網(wǎng)絡(luò)路由器設(shè)備,這其中任何一個(gè)路由器被黑客攻破,你們之間的通信數(shù)據(jù)就毫無(wú)保留的被別人看到。
所以,你需要用一個(gè)密鑰把數(shù)據(jù)加密吧。這樣A和B之間的數(shù)據(jù)就算被第三方看到,他們也不知道內(nèi)容是什么。可是這里又存在一個(gè)問題,A如何通知B(或者B如何通知A)它的密鑰是什么呢?要知道只要數(shù)據(jù)是在互聯(lián)網(wǎng)上傳輸,就有被截獲的可能。密鑰被截獲了,你就沒有秘密可言了。
現(xiàn)在我們需要考慮一個(gè)安全的方式來傳輸密鑰!讓我想想——非對(duì)稱加密!
- A、B之間建立TCP連接
- B生成一對(duì)公私密鑰
- B把公鑰發(fā)送給A
- A生成一個(gè)用于加密數(shù)據(jù)的密鑰K(既我們想通知給客戶端的密鑰,之后的數(shù)據(jù)通信都使用這個(gè)密鑰加密,這個(gè)密鑰不可讓第三方知道)
- A把K用公鑰加密發(fā)送給B,B解密后,從此A、B之間的通信數(shù)據(jù)都用K密鑰進(jìn)行加密和解密。
這樣假如中間的C、D、E截獲了A發(fā)給B的K密鑰內(nèi)容的數(shù)據(jù)包,可是這個(gè)密鑰是用B服務(wù)器生成的公鑰加密過的,只有B服務(wù)器知道如何解密。于是我們的數(shù)據(jù)很安全了。。。
看起來很簡(jiǎn)單不是嗎?一切大功告成。等等...如果黑客H埋伏在了A和B之間的某一個(gè)路由器上,他假冒B生成一對(duì)公私密鑰,然后把公鑰發(fā)送給A,這樣A與H之間就建成了一個(gè)加密通道,A把所有信息發(fā)送給H,H截獲A的信息,在假冒A與B通信。如此一來,A、B之間的通信就完全暴漏給了H,而A、B卻完全不知道,這就是有名的“中間人”攻擊。
為解決這個(gè)問題,SSH協(xié)議采用由人工判斷公鑰的fingerprint是否可信的方式。當(dāng)使用ssh命令連接服務(wù)器時(shí),命令行會(huì)提示如下信息:
The authenticity of host '168.30.9.213 (<no hostip for proxy command>)' can't be established.
RSA key fingerprint is 23:42:c1:e4:3f:d2:cc:37:1d:89:cb:e7:5d:be:5d:53.
Are you sure you want to continue connecting (yes/no)?
輸入yes之后才會(huì)連接到遠(yuǎn)程服務(wù)器,同時(shí)這個(gè)信息會(huì)存儲(chǔ)到用戶的.ssh/known_hosts文件中,下次再登錄的時(shí)候,會(huì)檢查known_host文件,如果存在相同的公鑰信息,就不在提示用戶確認(rèn)了。
這種認(rèn)證方式假設(shè)想登陸服務(wù)器的用戶已經(jīng)知道服務(wù)器公鑰(作為服務(wù)器的用戶他自然有渠道得知服務(wù)器公鑰)。fingerprint其實(shí)就代表公鑰,可以看成是公鑰的一個(gè)壓縮版。有了這個(gè)步驟,如果有中間人想冒充服務(wù)器B發(fā)送公鑰給A,它不可能生成一對(duì)和B生成的一樣的公私密鑰,他發(fā)送給A的公鑰必然與B服務(wù)器的不同,所以用戶就可以根據(jù)printfinger判斷所連接的服務(wù)器是否可信,有沒有被中間人冒充。
SSH的實(shí)現(xiàn)細(xì)節(jié)
上面只是粗略講解SSH的安全協(xié)議的設(shè)計(jì)思路,實(shí)際上SSH通信協(xié)議在安全通信過程中分了幾個(gè)階段,每個(gè)階段又細(xì)分了幾個(gè)步驟,具體的可參看SSH原理簡(jiǎn)介。幾個(gè)主要階段如下:
- 協(xié)議協(xié)商階段
- 服務(wù)端認(rèn)證階段
- 客戶端認(rèn)證階段
- 數(shù)據(jù)傳輸階段
客戶端認(rèn)證
這里我想單獨(dú)談?wù)効蛻舳苏J(rèn)證,因?yàn)閷?duì)于使用linux遠(yuǎn)程登錄功能的系統(tǒng)管理員來說能有直觀感覺的也就是是這個(gè)環(huán)節(jié)了。一般我們能接觸到的的認(rèn)證方式有兩種:
- 密碼認(rèn)證
- Public Key認(rèn)證
密碼認(rèn)證很好理解,就是我們?cè)诘卿涍h(yuǎn)程linux服務(wù)器的時(shí)候提供用戶名和密碼?這里面稍微提示一下,在你的用戶名和密碼通過網(wǎng)絡(luò)傳輸給服務(wù)器之前,已經(jīng)經(jīng)過了服務(wù)器認(rèn)證協(xié)商階段,這是一個(gè)安全的加密信道已經(jīng)建立,所以你的用戶名和密碼都是加密后傳輸給服務(wù)器的,保證不會(huì)被第三方截獲。
每次登錄都要輸入密碼很麻煩,且密碼如果簡(jiǎn)單的話可能還會(huì)被暴力破解。Public Key認(rèn)證提供了一種更安全便捷的認(rèn)證客戶端的方式。這個(gè)技術(shù)也用到了非對(duì)稱加密技術(shù),由客戶端生成公私密鑰對(duì),然后將公鑰保存在服務(wù)器上。認(rèn)證的過程大體如下:
- 客戶端發(fā)起一個(gè)Public Key的認(rèn)證請(qǐng)求,并發(fā)送RSA Key的模數(shù)作為標(biāo)識(shí)符。(如果想深入了解RSA Key詳細(xì) -->維基百科)
- 服務(wù)端檢查是否存在請(qǐng)求帳號(hào)的公鑰(Linux中存儲(chǔ)在~/.ssh/authorized_keys文件中),以及其擁有的訪問權(quán)限。如果沒有則斷開連接
- 服務(wù)端使用對(duì)應(yīng)的公鑰對(duì)一個(gè)隨機(jī)的256位的字符串進(jìn)行加密,并發(fā)送給客戶端
- 客戶端使用私鑰對(duì)字符串進(jìn)行解密,并將其結(jié)合session id生成一個(gè)MD5值發(fā)送給服務(wù)端。*結(jié)合session id的目的是為了避免攻擊者采用重放攻擊(replay attack)。
- 服務(wù)端采用同樣的方式生成MD5值與客戶端返回的MD5值進(jìn)行比較,完成對(duì)客戶端的認(rèn)證。
為更廣大群眾設(shè)計(jì)的SSL與TLS
上面wiki上也有寫,SSH其實(shí)是專門為shell設(shè)計(jì)的一種通信協(xié)議,它垮了兩個(gè)網(wǎng)絡(luò)層(傳輸層和應(yīng)用層)。通俗點(diǎn)講就是只有SSH客戶端,和SSH服務(wù)器端之間的通信才能使用這個(gè)協(xié)議,其他軟件服務(wù)無(wú)法使用它。但是其實(shí)我們非常需要一個(gè)通用的,建立在應(yīng)用層之下的一個(gè)傳輸層安全協(xié)議,它的目標(biāo)是建立一種對(duì)上層應(yīng)用協(xié)議透明的,不管是HTTP、FTP、還是電子郵件協(xié)議或其他任何應(yīng)用層協(xié)議都可以依賴的底層的可安全通信的傳輸層協(xié)議。
網(wǎng)景公司于1994年為解決上面的問題,設(shè)計(jì)了SSL(Secure Sockets Layer)協(xié)議的1.0版本,但并未發(fā)布,直到1996年發(fā)布SSL3.0之后,開始大規(guī)模應(yīng)用于互聯(lián)網(wǎng)服務(wù)??赡芎芏嗳寺犓^TLS(Transport Layer Security)。它相當(dāng)于是SSL協(xié)議的一個(gè)后續(xù)版本,他是SSL經(jīng)過IETF標(biāo)準(zhǔn)化之后的產(chǎn)物(詳細(xì)參考傳輸層安全協(xié)議,下文中所說的SSL協(xié)議也包括TSL)。
跟SSH相比SSL所面臨的問題要更復(fù)雜一些,上面我們提到,SSH協(xié)議通過人工鑒別Public Key的printfinger來判斷與之通信的服務(wù)器是否可信(不是偽裝的中間人)??墒荢SL是為了整個(gè)互聯(lián)網(wǎng)上的所有客戶端與服務(wù)器之間通信而設(shè)計(jì)的,他們彼此之間不可能自己判斷通信的對(duì)方是否可信。那么如何解決這個(gè)問題呢?
在構(gòu)思解決方案之前我先講一個(gè)概念數(shù)字簽名。。。。
想了一下,還是不寫了。。。 阮老師的這篇blog對(duì)數(shù)字簽名解釋的非常到位,良心推薦,如果有不了解數(shù)字簽名概念的讀者,建議先看看阮老師的文章。
回到上面我們所要解決的問題,以瀏覽器和網(wǎng)站服務(wù)器之前的安全通信舉例,首先瀏覽器要求和某WEB服務(wù)器建立安全的SSL連接通道,這時(shí)需要服務(wù)器的公鑰用來加密瀏覽器生成的通信密鑰,發(fā)給WEB服務(wù)器,以確定通信密鑰。假如瀏覽器接受到一個(gè)公鑰,它如何知道這個(gè)公鑰確實(shí)是來自那個(gè)WEB服務(wù)器,而不是中間的某個(gè)攻擊者截獲了它的請(qǐng)求,假扮WEB服務(wù)器給它的假密鑰?瀏覽器總不能記錄所有可信任站點(diǎn)的公鑰吧。
解決問題的思路是這樣的,在SSL協(xié)議中引入了一種類似公共機(jī)關(guān)(類似于我國(guó)的國(guó)家公證處?)的概念,就是我們熟知的CA(數(shù)字證書認(rèn)證機(jī)構(gòu))。它為瀏覽器發(fā)行一個(gè)叫數(shù)字證書的東西。這個(gè)東西大體上如下圖所示,其中比較重要的信息有:
- 對(duì)象的公開密鑰
- 數(shù)字簽名
有了數(shù)字證書,瀏覽器在建立SSL連接之前,并不只是簡(jiǎn)單獲取服務(wù)器的公鑰,而從服務(wù)器獲取數(shù)字證書。數(shù)字證書里有服務(wù)器的公鑰,并且有CA給這個(gè)證書簽發(fā)的簽名。這個(gè)簽名其實(shí)是證書內(nèi)容的摘要經(jīng)過CA私鑰加密生成的。這樣瀏覽器得證書內(nèi)容和摘要,并用CA的公鑰(每個(gè)瀏覽器都存儲(chǔ)著一些權(quán)威CA的公鑰)對(duì)數(shù)字簽名解密,也得到證書的摘要,比對(duì)兩個(gè)摘要如果相同,說明證書是真的,且未經(jīng)過修改。信任問題就這么解決了,如果上面這段話不好理解的話,再次建議讀一讀阮老師的數(shù)字簽名是什么?。

其他SSL的握手,密鑰交換,加密的細(xì)節(jié)這里就不介紹了,普通開發(fā)者這要懂上面我介紹的這些基本概念就可以了。
HTTPS
讀完上面內(nèi)容,理解HTTPS就簡(jiǎn)單了,它的全稱是 Hypertext Transfer Protocol Secure,也稱為HTTP over TLS, HTTP over SSL,其實(shí)就客戶端與服務(wù)系之間的HTTP通信基于TLS或則SSL協(xié)議。對(duì)于HTTP協(xié)議和SSL/TLS協(xié)議本身沒有任何特殊定制,因?yàn)镾SL/STL本身對(duì)HTTP協(xié)議就是透明的,HTTP在SSL/TLS上運(yùn)作也不需要任何特殊處理。
做為網(wǎng)站管理員,可能會(huì)遇到申請(qǐng)數(shù)字證書的任務(wù),理解了上面的概念,申請(qǐng)數(shù)字證書就不那么一頭霧水了,首先你要為服務(wù)器生成一對(duì)公司密鑰,然后把你網(wǎng)站的信息連同你的公鑰一起發(fā)送給某個(gè)權(quán)威的CA,CA會(huì)通過某種方式認(rèn)證申請(qǐng)人是否真的是網(wǎng)站的所有人,比如讓你在網(wǎng)站的指定路徑上傳他指定的特殊蚊子序列。驗(yàn)證通過就會(huì)得到證書了。
思考題
通過代理訪問HTTPS協(xié)議的網(wǎng)站,你的通信是否安全?
強(qiáng)烈推薦《HTTP權(quán)威指南》這本書,你會(huì)驚奇的發(fā)現(xiàn)15年前寫的書,里面的內(nèi)容今天來讀不但一點(diǎn)都不過是,且會(huì)收獲很多。
參考文獻(xiàn)
RSA算法原理(一)
數(shù)字簽名是什么?
SSH原理簡(jiǎn)介
SSL/TLS協(xié)議運(yùn)行機(jī)制的概述