項目中遇到了解籤解密,之前就曾經遇到過加密的問題,項目中也曾經遇到過這樣的需求,但一直都沒有系統的瞭解,正好這次一起把這塊東西搞清楚。
數據傳輸安全的要求
首先我們先明確我們在數據傳輸時對於安全到底有什麼具體要求:
- 消息的發送方能夠確定消息只有預期的接收方可以解密(不保證第三方無法獲得,但保證第三方無法解密)。
- 消息的接收方可以確定消息是由誰發送的(消息的接收方可以確定消息的發送方)。
- 消息的接收方可以確定消息在途中沒有被篡改過(必須確認消息的完整性)。
關於加密
針對安全三個要求中的第一個要求,我們可以通過加密的方式解決。那麼加密大致又分爲對稱加密和非對稱加密,那麼什麼是對稱加密,什麼有是非對稱加密呢?
(一)對稱加密
對稱加密(也叫私鑰加密)指加密和解密使用相同密鑰的加密算法。有時又叫傳統密碼算法,就是加密密鑰能夠從解密密鑰中推算出來,同時解密密鑰也可以從加密密鑰中推算出來。而對稱算法的安全性依賴於密鑰,泄漏密鑰就意味着任何人都可以對他們發送或接收的消息解密,所以密鑰的保密性對通信性至關重要。在1976年以前,所有的加密都採用對稱加密。
對稱加密算法的特點是算法公開、計算量小、加密速度快、加密效率高。
不足之處是,交易雙方都使用同樣鑰匙,安全性得不到保證。
具體算法:DES算法,3DES算法,TDEA算法,Blowfish算法,RC5算法,IDEA算法。
其中最經典的算法莫過於DES加密算法。DES加密採用的是分組加密的方法,使用56位密鑰加密64位明文,最後產生64位密文。流程如下,大致瞭解即可。
(二)非對稱加密
在1976年有兩位數學家提出了一個嶄新的非對加密的概念:
1.A生成一對兩把密鑰(公鑰和私鑰)。公鑰是公開的,任何人都可以獲得,私鑰則是保密的。
2.B獲取乙方的公鑰,然後用它對信息加密。
3.A得到加密後的信息,用私鑰解密。
受這個思路的啓發,三位數學家Rivest、Shamir 和 Adleman 設計了一種具體實現上面描述的非對稱加密的算法,以他們三個人的名字命名,就是目前在計算機領域應用非常廣泛的非對稱加密算法RSA加密算法。想深入理解非對稱加密解密的原理可以看這裏。
主要算法:RSA、Elgamal、揹包算法、Rabin、HD,ECC(橢圓曲線加密算法)。
雖然非對稱加密很安全很強大,但是它也有缺點,相對於對稱加密它計算量更大,計算時間更長。所以在大規模數據的安全通信場景中,普遍採用非對稱加密技術來交換對稱加密密鑰,之後的通信都採用對稱加密技術加密。
關於簽名
利用加密我們滿足了第一個要求,數據只有預期的接受方纔能解密,但是在這個過程如何保證數據的完整性,保證數據是發送方發送的數據,而不是被第三方篡改後的數據,也就是第三點的要求,這時候就要用到簽名。
在發送方加密明文之前,給明文取md5值,得到其信息的摘要(注:不能通過信息摘要反推明文)。然後用公鑰分別給明文和明文的摘要加密發送到數據的接收方,數據的接收方接收到數據之後,用私鑰對密文和摘要進行解密,然後對解密得到的明文取md5摘要,比對解密後的明文摘要和發送過來的摘要是否一致;一致就證明數據是原始的數據沒有遭到篡改。
下面是圖解過程:
關於認證模式
講到這裏,其實非對稱加密算法中信息的發送方和接收方都分別有兩個密鑰,其中分別爲私鑰和公鑰(各自的私鑰和彼此的公鑰),私鑰爲數據的發送方持有,公鑰可以公開。其中涉及到兩種模式,它們分別爲加密模式和認證模式。
在認證模式中,發送方用私鑰加密數據,給接收方發送數據,接收方用公鑰解密,因爲私鑰是唯一的,所以只要數據解析成功就可以知道數據發送方是誰。
這樣第二點的要求也達成了。
總結
結合以上,我們再來整理一下發送方和接收方所做的事情。
發送方:
- 將消息進行散列運算,得到消息摘要。
- 使用自己的私鑰對消息摘要加密(認證模式:確保了接收方能夠確認自己)。
- 使用接收方的公鑰對消息進行加密(加密模式:確保了消息只能由期望的接收方解密)。
- 發送消息和消息摘要。
接收方:
- 使用發送方的公鑰對消息摘要進行解密(確認了消息是由誰發送的)。
- 使用自己的私鑰對消息進行解密(安全地獲得了實際應獲得的信息)。
- 將消息進行散列運算,獲得消息摘要。
- 將上一步獲得的消息摘要 和 第一步解密的消息摘要進行對比(確認了消息是否被篡改)。
證書機制
與數字簽名相關的一個概念就是證書機制了,證書是用來做什麼呢?在上面的各種模式中,我們一直使用了這樣一個假設,就是接收方或者發送方所持有的、對方的公鑰總是正確的(確實是對方公佈的)。而實際上除非對方手把手將公鑰交給我們,否則如果不採取措施,雙方在網絡中傳遞公鑰時,一樣有可能被篡改。那麼怎樣解決這個問題呢?這時就需要證書機制了:可以引入一個公正的第三方,當某一方想要發佈公鑰時,它將自身的身份信息及公鑰提交給這個第三方,第三方對其身份進行證實,如果沒有問題,則將其信息和公鑰打包成爲證書(Certificate)。而這個公正的第三方,就是常說的證書頒發機構(Certificate Authority)。當我們需要獲取公鑰時,只需要獲得其證書,然後從中提取出公鑰就可以了。
SSH SSL與HTTPS
談完數據傳輸安全,不得不提到這幾個具體應用的協議了。
(一)SSH
Secure Shell(縮寫爲SSH),由IETF的網絡工作小組(Network Working Group)所制定;SSH爲一項創建在應用層和傳輸層基礎上的安全協議,爲計算機上的Shell(殼層)提供安全的傳輸和使用環境。
傳統的網絡服務程序,如rsh、FTP、POP和Telnet其本質上都是不安全的;因爲它們在網絡上用明文傳送數據、用戶帳號和用戶口令,很容易受到中間人(man-in-the-middle)攻擊方式的攻擊。就是存在另一個人或者一臺機器冒充真正的服務器接收用戶傳給服務器的數據,然後再冒充用戶把數據傳給真正的服務器。
而SSH是目前較可靠,專爲遠程登錄會話和其他網絡服務提供安全性的協議。利用SSH協議可以有效防止遠程管理過程中的信息泄露問題。通過SSH可以對所有傳輸的數據進行加密,也能夠防止DNS欺騙和IP欺騙。
SSH之另一項優點爲其傳輸的數據可以是經過壓縮的,所以可以加快傳輸的速度。SSH有很多功能,它既可以代替Telnet,又可以爲FTP、POP、甚至爲PPP提供一個安全的“通道”。
而ssh的數據傳輸就用到了非對稱加密,但是仍存在一個問題,假設A與B之間通信,利用非對稱機密,B生成了一對公鑰私鑰,但在B將公鑰傳輸給A的過程中,出現了C,C假冒了B生成了一堆公鑰私鑰,然後把公鑰傳給A,和A建立了加密通道,獲取了所有A要發送給B的信息。這就是著名的“中間人”攻擊。
爲解決這個問題,SSH協議採用由人工判斷公鑰的fingerprint是否可信的方式。當使用ssh命令連接服務器時,命令行會提示如下信息:
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之後纔會連接到遠程服務器,同時這個信息會存儲到用戶的.ssh/known_hosts文件中,下次再登錄的時候,會檢查known_host文件,如果存在相同的公鑰信息,就不在提示用戶確認了。
這種認證方式假設想登陸服務器的用戶已經知道服務器公鑰(作爲服務器的用戶他自然有渠道得知服務器公鑰)。fingerprint其實就代表公鑰,可以看成是公鑰的一個壓縮版。有了這個步驟,如果有中間人想冒充服務器B發送公鑰給A,它不可能生成一對和B生成的一樣的公私密鑰,他發送給A的公鑰必然與B服務器的不同,所以用戶就可以根據printfinger判斷所連接的服務器是否可信,有沒有被中間人冒充。
具體的實現細節可參看SSH原理簡介
(二)SSL與TLS
SSH其實是專門爲shell設計的一種通信協議,它垮了兩個網絡層(傳輸層和應用層)。通俗點講就是隻有SSH客戶端,和SSH服務器端之間的通信才能使用這個協議,其他軟件服務無法使用它。但是其實我們非常需要一個通用的,建立在應用層之下的一個傳輸層安全協議,它的目標是建立一種對上層應用協議透明的,不管是HTTP、FTP、還是電子郵件協議或其他任何應用層協議都可以依賴的底層的可安全通信的傳輸層協議。
網景公司於1994年爲解決上面的問題,設計了SSL(Secure Sockets Layer)協議的1.0版本,但並未發佈,直到1996年發佈SSL3.0之後,開始大規模應用於互聯網服務。
跟SSH相比SSL所面臨的問題要更復雜一些,上面我們提到,SSH協議通過人工鑑別Public Key的printfinger來判斷與之通信的服務器是否可信(不是僞裝的中間人)。可是SSL是爲了整個互聯網上的所有客戶端與服務器之間通信而設計的,他們彼此之間不可能自己判斷通信的對方是否可信。那麼如何解決這個問題呢?
這時候就要用到上述提到的證書機制,證書主要包含了
- 對象的公開密鑰
- 數字籤名
如下圖所示:
因此,利用證書機制就完美瞭解決了信任問題。
(三)HTTPS
讀完上面內容,理解HTTPS就簡單了,它的全稱是 Hypertext Transfer Protocol Secure,也稱爲HTTP over SSL,其實就客戶端與服務系之間的HTTP通信基於SSL協議。
對於HTTP協議和SSL協議本身沒有任何特殊定製,因爲SSL本身對HTTP協議就是透明的,HTTP在SSL上運作也不需要任何特殊處理。
base64
這邊還要提下base64,起初以爲這也是一種加密算法,其實不是,百度百科中對Base64有一個很好的解釋:“Base64是網絡上最常見的用於傳輸8Bit字節碼的編碼方式之一,Base64就是一種基於64個可打印字符來表示二進制數據的方法”。也就是說,它其實只是一種編碼格式。
Base64一般用於在HTTP協議下傳輸二進制數據,由於HTTP協議是文本協議,所以在HTTP協議下傳輸二進制數據需要將二進制數據轉換爲字符數據。然而直接轉換是不行的。因爲網絡傳輸只能傳輸可打印字符。什麼是可打印字符?在ASCII碼中規定,0~31、128這33個字符屬於控制字符,32~127這95個字符屬於可打印字符,也就是說網絡傳輸只能傳輸這95個字符,不在這個範圍內的字符無法傳輸。那麼該怎麼才能傳輸其他字符呢?其中一種方式就是使用Base64。
也就是說,如果將索引轉換爲對應的二進制數據的話需要至多6個Bit。然而ASCII碼需要8個Bit來表示,那麼怎麼使用6個Bit來表示8個Bit的數據呢?6個Bit當然不能存儲8個Bit的數據,但是4*6個Bit可以存儲3*8個Bit的數據啊!如下表所示:
可以看到“Son”通過Base64編碼轉換成了“U29u”。這是剛剛好的情況,3個ASCII字符剛好轉換成對應的4個Base64字符。但是,當需要轉換的字符數不是3的倍數的情況下該怎麼辦呢?Base64規定,當需要轉換的字符不是3的倍數時,一律採用補0的方式湊足3的倍數,具體如下表所示:
每6個Bit爲一組,第一組轉換後爲字符“U”,第二組末尾補4個0轉換後爲字符“w”。剩下的使用“=”替代。即字符“S”通過Base64編碼後爲“Uw==”。這就是Base64的編碼過程。