安全通信
應用層協議大多數自己都沒有實現加解密功能,比如http等。http就是直接把數據加載進來然后做簡單編碼(也就是流式化)然后響應客戶端,然后數據在瀏覽器展示,這個數據在傳輸過程是明文的,你截獲就可以直接查看。這顯然不安全,要想做到安全那么就只能在發送端加密然后接收端還能把信息還原成原來的內容,這就是加密解密。其實這個事情很好理解,加密解密在古代就有也不是現代的概念。在安全通信里面我經常聽到的2個東西就是SSL和TLS,這2個有什么區別呢?以及HTTPS是怎么通信的?
SSL和TLS
SSL
SSL是網景公司研發的一種功能模塊這種模塊或者叫庫就在應用層和傳輸層之間又加了一層,而且不是一整層只是半層,這要做的好處是你調用這個庫就可以使用這個功能如果不調用則還是按照之前的方式來使用,這個半層的庫就是SSL,叫做安全套接字層。不過SSL只是一種規范和協議並不是具體實現。OpenSSL則是對SSL的實現而且眾多實現中的一種。什么叫做一種實現呢?比如httpd和Nginx這兩個應用都是http協議的實現或者說x86是一種標准那么DELL和HP都可以基於這種標准來設計自己的電腦。
如果你自己本身不具備開發這種加密解密的功能,那么你就可以使用SSL完成這個工作,不過無論你自己開發還是使用SSL,這些加密解密協議都需要具備2個基本功能:
-
加密和解密
-
秘鑰分發
在Web應用方面,http調用了ssl就變成了https,雖然就是調用了ssl,但是http和https這兩個在機制上有巨大的區別。
TLS
叫做傳輸層安全,為什么有了SSL還會有一個和SSL類似的TLS呢?因為SSL協議是發明者是網景公司,它擁有版權,而且互聯網公司很多都需要使用安全通信,所以國際標准化機構就參照SSL弄了一個TLS協議。兩者兼容。TLS由IETF在1999年發布。那么由於SSL的3個版本有漏洞所有很多不用了。現在主流都使用TLS。總之你可以把TLS當做SSL使用其原理都是一樣的。
早期使用SSL較多后來大部分使用TLS,雖然我們平時會說ssl它可能指的是SSL也可以是TLS,所以你不用糾結它指的是什么你只要理解為一種安全通信機制就可以。所以我們后面會不加區分的統稱SSL。
為什么現在都是全站啟用SSL呢
之前很多網站都不是https,也只有某些特殊階段才使用,比如支付階段、登錄驗證階段。那么后來為什么大家包括百度搜索首頁這種都變成https了呢?
如果使用SSL加密那么服務端就需要解密,加解密其實非常消耗CPU資源,早期處於性能考慮不會大面積使用SSL,比如只是普通的瀏覽網頁沒必要進行安全通信。但是后來服務器性能越來越強而且大規模使用x86服務器以及有些網卡也支持SSL卸載,所以全站使用SSL也成為可能。
不過由於http是明文傳輸的,用戶訪問什么網頁其實可以通過流量攔截,數據可以被修改,有些不法行為就可以利用這一點來實現廣告投放,但是使用https通信則不會出現這種情況。
安全通信到底怎么安全呢?
基本概念
為了解決安全問題實現安全目標比如保密性、完整性、可用性等其解決方案有兩類,就是技術和服務,技術指的是加密和解密;服務指的是認證機制和訪問控制機制。
針對加密和解密以及實現服務功能的所用到的加密算法和協議就有如下幾種:對稱加密、非對稱加密、單向加密和認證協議。
在Linux上實現上述算法和協議的工具有OpenSSL(ssl協議的實現)和GPG(pgp協議的實現)。
數字加密算法
先說一下算法,雖然加密用秘鑰但是如何用這個秘鑰來對數據加密或者解密這個是算法來決定的,但是通常算法是公開的比如RSA(個別安全公司有自己的獨有的算法除外)所以是否安全不取決於算法而是秘鑰。
什么叫密碼,什么叫秘鑰?我上面那段話肯定會有人迷糊,密碼是編碼和解碼的規則你可以理解為加密和解密規則而秘鑰則是改變密碼行為的外在參數,也就是說相同的規則當你使用不同的秘鑰加密相同內容時加密后的結果也是不同的。比如字母移位這就是密碼,而移動N位的這個N則是秘鑰。假設移動3位,那么ABC則變成DEF。所以這就是為什么上面那段話的結論是不取決於算法(密碼)而是秘鑰。
對稱秘鑰加密:對稱加密算法有很多,但是無論什么算法加密解密都使用相同的秘鑰,好處是簡單計算量小也就是不會對CPU產生太大壓力,缺點以及密碼過多(你要和很多人通信就需要很多人的密碼)、密碼分發困難。因為你要讓對方可以解密你就需要把密碼先給對方,這個給密碼的過程要不要加密呢?這就變成了先有雞還是先有蛋的事情永遠扯不清。常用算法DES(目前已經棄用)、AES等。
非對稱秘鑰加密:有公鑰和私鑰,使用公鑰加密私鑰解密。如果A和B通信每個人都有一對兒公鑰和私鑰,彼此還都有對方的公鑰。A發信息給B則使用B的公鑰加密,然后B收到后使用自己的私鑰解密,然后B回復信息給A則使用A的公鑰加密,A收到后使用自己的私鑰解密。這個過程看似完美,可是由於公鑰大家都能獲取,B怎么知道信息是來自A而不是來自其他冒名A的人呢?這就是數字簽名,這個后面再說。非對稱加密主要用於數字簽名和秘鑰交換。加密數據雖然它也能做但是通常不這么用,你看后面的HTTPS通信過程就知道了。非對稱加密主要用來做對稱秘鑰的交換,完成交換后大家其實就是使用對稱密碼來做數據加密和解密。常用算法RSA(加解密和簽名)、DSA(僅能簽名)等。
單向加密**:不可逆的,只能加密不能解密,比如MD5、SHA1等。其實主要用來提取數據摘要或者說指紋,所以並不能算作我們常規意義上的加密。它的特點是數據微小變化都會導致指紋的不同,所以主要用來做數據完整性驗證。
特別注意:並不是說只能用公鑰加密私鑰解密,非對稱加密方式的目的就是使用一種秘鑰加密的數據必須能使用另外一種秘鑰解密,所以無論是公鑰還是私鑰都可以加密,我們之所以說用公鑰加密用私鑰解密是首先是因為公鑰是從私鑰中提取出來的,其次公鑰是公開的如果你用私鑰加密那么任何擁有該私鑰對應公鑰的人都可以解密 。所以才有公鑰發給其他人私鑰自己留存且用公鑰加密私鑰解密,因為只有這樣才能發揮這種非對稱加密或者說公鑰加密的主要作用也就是密碼交換和數字簽名。不過使用私鑰加密數據可以證明一件事情就是如果用該私鑰的公鑰可以解密那就證明這個數據一定是私鑰持有人發來的。
秘鑰交換(IKE,互聯網秘鑰交換):IKE實現的方式有公鑰加密和DH算法。這種標准主要用來做秘鑰交換。不過對於秘鑰交換來說更加安全的其實是DH算法,雖然常用的是公鑰加密方式。
公鑰加密最大的問題是密碼是要從一方傳送到一方,雖然使用對方的公鑰加密了。但是DH的好處是雙方不用發密碼而且雙方還可以得到密碼。
數字簽名
數字簽名的主要作用是為了檢查數據是否被篡改以及數據是誰發的(就是向對方證明此時他收到的消息是來自消息宣稱的人本人而不是冒名頂替的第三人,當然真正驗證對方身份的還不能僅僅靠數字簽名這個后面再說)。
按照上面的例子A發消息給B,A使用B的公鑰加密,B通過自己的私鑰解密,可是公鑰大家都可以獲得那么B怎么知道這個消息是來自A呢?難道僅僅憑借消息內容說我是A就斷定消息來自A么?另外B怎么確定信息在傳遞過程中沒有被篡改呢?
為了解決這個問題A對消息做哈希摘要(MD5算法或者SHA1算法等)然后用A自己的私鑰對摘要進行加密(數字簽名),然后把加密后的摘要和消息本身一起使用B的公鑰加密發送給B,這樣B收到消息后用自己的私鑰可以解密,然后用A的公鑰可以解密簽名(上面提到的摘要)如果成功就說明消息來自A。這就是簽名和驗證簽名過程。消息來源確認了,此時就會擔心消息傳遞過程中如果被篡改怎么辦?這就是那段被加密的摘要的作用,如果B使用相同的算法來計算信息的摘要,如果B計算得到的值和解密簽名后的得到的值一致說明信息沒有被篡改。
上面的過程的確看起來很好但是有一個漏洞就是所有的公鑰都要自己保存和管理萬一被別人替換了呢,或者說A和B從未通信過現在要做第一次通信如何把公鑰給對方呢?難道就不怕有人冒充A把自己的公鑰給了B那么反過來也是一樣,另外A對信息做哈希摘要的時候用的什么算法,萬一B沒有這個算法怎么辦呢,所以這就引出了CA和證書的概念。
為什么需要CA、證書以及CA根證書
公鑰加密私鑰解密,私鑰肯定是自己保存其實也就保存一份,如果我需要給很多人通信難道我要保存很多人的公鑰么?如果這個數量達到一個量級在管理上也很困難另外就是如何防止公鑰被篡改呢也就是如何驗證這個公鑰是不是我要通信的那個人的公鑰而不是別人發來冒充他的。如果要是有一個第三方機構來統一管理就好了,這就是CA證書管理機構。CA的作用就是對申請人的公鑰進行認證和加密,加密后的公鑰就是數字證書,又稱CA證書,證書中包含了很多重要信息比如申請人、用途、申請人支持的加密算法、申請人使用hash算法,證書有效期等其中最重要的就是證書申請人的公鑰。當然前提是通信雙方都要信任同一個CA機構。
那有了CA之后該怎么做呢?申請者需要自己生成自己的公鑰和私鑰,然后把公鑰和其他申請信息發給證書頒發機構,證書頒發機構自己也有公鑰和私鑰,然后證書頒發機構提取申請者的公鑰和其他信息的特征碼,然后CA使用自己的私鑰加密這個特征碼也就是簽名, 這樣形成一個由CA簽名的證書然后發送給申請者 。此時還是A和B通信且為第一次通信並且雙方都信任同一CA頒發機構 。
- A把自己支持的對稱加密算法、單向加密算法、公鑰加密算法以及自己的證書發給B
- B拿到信息后需要對A的證書解密(這樣才能獲取A的公鑰),但證書是CA用私鑰加密的需要用CA的公鑰解密這怎么辦?這就是CA根證書(包含CA的公鑰)的作用,B需要下載CA根證書並且安裝到自己的電腦里通常只需要安裝一次(通常現在操作系統 MacOX、Windows都已經內置了國際著名CA的根證書,因為全球著名CA都是有限的,Linux沒有內置)。有了這個根證書也就有了CA的公鑰,這樣就可以解密A的證書來獲取A的公鑰。能解密成功說明A的證書是CA頒發的。然后使用證書中的單向加密算法來計算證書的特征碼如果和解密簽名得到的特征碼一致則表明內容沒有被篡改,所以這一步完成了對A的身份驗證和證書信息的完整性驗證。
- 驗證完之后還要看該證書的有效期以及證書主體名稱和該證書是否被吊銷
- 驗證都通過之后B選擇自己支持的對稱加密算法、單向加密算法、公鑰加密算法以及自己的證書發送給A
- A采用相同的步驟來驗證B,如果驗證通過,這時候大家就確定了使用哪種對稱加密算法、單向加密算法、公鑰加密算法並且完成了雙方的公鑰交換以及身份驗證
- A使用對稱加密算法生成一個密碼,然后對密碼計算摘要,然后用自己的私鑰對摘要進行簽名,之后用B的公鑰進行加密發送給B
- B收到信息后使用自己的私鑰解密,然后使用A的公鑰解密簽名得到摘要,如果解密成功則說明是A發來的,然后對密碼提取摘要並和解密簽名得到的摘要對比,如果一直則說明信息完整,這時候就完成了密碼交換,從此雙發就可以使用對稱加密方式來通信。
上述這個過程就是大家通過CA來間接獲取通信雙方公鑰的過程。如果B使用CA的根證書無法解密A發來的證書說明就說明A的證書不是該CA簽發的,由於世界上公認的CA也就那么幾個所以如果B用這些CA的根證書都解密不了A的證書,那么就會提示風險,很有可能A這個證書就是一個自簽名的證書。
這里我們只是闡明概念,在實際應用中上述過程還有些不同,比如上面A發給B的包括簽名和證書以及信息,難道信息不加密么?如果加密用什么加密等。這些東西都會在具體應用場景中再說明。
既然明白了CA那么我們就說一下PKI。
PKI
公鑰基礎設施,以CA為中心所生成的一套體系就是PKI。它有四個重要組件:
-
簽證機構,就是CA,這個是負責生成證書的
-
注冊機構,就是RA,這個是負責接收證書申請的
-
證書吊銷列表,就是CRL,這個是標記哪些證書已經不可用或者不可信了,相當於證書黑名單,這里的證書都不能被信任了。
-
證書存取庫,就是CB,這里存放的是CA發的證書可以供其他人下載和使用
證書常用字段和格式
首先要說一下X.509,它就是證書標准,也叫做證書格式。所有證書都要符合這個標准,它定義了證書中包含那些內容。比如版本號、序列號(CA發的第幾個證書)、簽名算法ID(這個證書用什么算法做的簽名)、CA頒發機構名稱、證書有效期、申請者名稱、申請者公鑰、CA頒發機構的唯一標識、申請者的唯一標識、CA對該證書的簽名(用CA自己的私鑰對所有信息的摘要做簽名)等擴展信息。下面就看看證書中常見的字段:
字段 | 含義 |
---|---|
Common Name | 簡稱CN,對於SSL證書來說一般為網站域名;而對於代碼簽名證書則為申請單位名稱;而對於客戶端證書來說則是申請者名稱也可以當做用戶賬號名稱 |
Organization Name | 簡稱O,對於SSL證書來說一般為網站域名;而對於代碼簽名證書則為申請單位名稱;而對於客戶端證書來說則是申請者名稱也可當做用戶賬號所屬的組 |
Locality | 簡稱L,表示城市 |
State/Provice | 簡稱ST,表示省份 |
Country | 簡稱C,表示國家,比如中國為CN,美國為US |
瀏覽器使用HTTPS訪問時它是怎么檢查證書和地址欄中的名稱呢?有下面三種方式
- 主機名(地址欄中的域名)與證書Subject中的CN字段完全匹配
- 主機名稱與通配符通用名稱相匹配,比如www.abc.com匹配通用名稱*.abc.co
- 主機名在主題備用名稱(Subject Alternative Name檢查sans)字段中列出
我們知道了X.509是證書格式,可是很多時候看到的.pem、.key都什么呢?,這里就要做一些區分,證書編碼格式和證書擴展名。
證書編碼格式
所有的證書都是通過X.509標准生成的證書,但是有2中編碼格式:
-
PEM(Privacy Enhanced Mail),它是基於X.509標准生成的,文件可讀可以直接打開查看,它是以"-----BEGIN CERTIFICATE-----" 和 "-----END CERTIFICATE-----"開頭和結尾且用Base64編碼的證書,這種編碼格式的證書通常是.pem擴展名。
使用命令
openssl x509 -in XXX.pem -text -noout
來查看證書內容。 -
DER(Distinguished Encoding Rules),二進制格式的,無法直接讀取。
使用命令 openssl x509 -in XXX.der -inform der -noout 來查看證書內容。
證書擴展名
雖然證書編碼格式有2種,但是擴展名有很多:
擴展名 | 說明 |
---|---|
.der | 用於DER編碼的證書 |
.pem | 它是基於X.509標准生成的,它是以"-----BEGIN CERTIFICATE-----" 和 "-----END CERTIFICATE-----"開頭和結尾且用Base64編碼的證書 |
.crt | 這種擴展名的證書可以是DER編碼也可以是PEM編碼,在Unix系統中常見。 |
.cer | 微軟系統常見,在微軟系統中可以將.crt轉換為.cer。同樣可以是DER編碼也可以是PEM編碼。 |
.key | 用於存儲公鑰和私鑰,同樣可以使用DER或者PEM編碼。 |
.csr | 這個不是證書文件,而是證書簽名請求文件,向CA申請獲得簽名證書時需要提供的申請文件。 |
HTTPS通信過程
雙向認證
上圖為SSL的雙向驗證過程
- 瀏覽器發起https請求,生成隨機數(用於稍后生成會話秘鑰),並發送client_hello信息里面將自己支持的加密協議版本、加密算法、壓縮算法和生成的隨機數發送給服務端。
- 服務端收到信息以后,也生成隨機數(用於稍后生成會話秘鑰),並發送server_hello信確認自己客戶端發送來的協議版本、算法等。如果不支持那么就無法通信了。
- 服務端發送服務器證書給客戶端,並且要求客戶端也發送證書過來
- 客戶端檢查服務端證書合法性和有效性,通過以后,發送客戶端證書給服務端
- 服務器檢查客戶端的證書合法
- 客戶端把所有之前收到的信息做HASH,然后使用自己私鑰做簽名,發送給服務器端
- 服務端檢查哈希值和簽名
- 客戶端使用對稱加密算法生成一個加密密碼,然后使用客戶端公鑰進行加密發送給服務端
- 服務端收到以后就可以使用對稱加密密碼和客戶端通信
- 斷開連接
單向認證
HTTPS訪問通常使用單向認證,比如你訪問百度、淘寶、京東等雖然是https通信但是它們不會去驗證客戶端證書,客戶端只會去驗證服務端證書。為什么呢?因為證書花錢啊,哪個網站要是需要做客戶端證書認證那么估計就沒有人去訪問了,再有對於服務端來說它不在乎你是誰來的人越多越好。當然也有通信雙方要求做雙向認證的比如登錄網銀的U盾就是客戶端證書。
-
瀏覽器發起https請求,生成隨機數將自己支持的一套加密規則、協議版本發送給服務端。
-
服務端從中選出一組加密算法與HASH算法,服務端也生成一個隨機數並將自己的身份信息以證書的形式發回給瀏覽器。證書里面包含了服務端地址,加密公鑰,以及證書的頒發機構等信息。
-
客戶端獲得服務端證書之后瀏覽器要做以下工作:(驗證我訪問的www.abc.com是不是真正的那個www.abc.com,這個驗證過程就通過服務端證書和自己的CA根證書來完成)
-
驗證證書的合法性和有效性(使用客戶端保存的CA根證書的公鑰解密服務端發來的證書的簽名,解密成功說明服務端證書可以信任,然后使用HASH算法計算證書摘要然后對比解密簽名后得到的摘要,如果一致則說明內容沒有篡改,然后 檢查證書中的其他信息,可以檢查證書中的域名和我訪問的域名是否一致 (這里防止釣魚網站)、檢查是否過期、檢查是否被吊銷等,如果檢查都通過則證書受信任,則瀏覽器欄里面會顯示一個小鎖頭,否則會給出證書不受信的提示。
-
如果證書受信任,或者是用戶接受了不受信的證書,瀏覽器會生成一串隨機數,然后把隨機數、編碼變更通知(表示隨后的通信都使用雙方商定的協議版本以及加密算法)和客戶端握手結束通知發送給服務器
-
-
服務端接收瀏覽器發來的數據之后要做以下的操作:
-
這時候服務端會有3個隨機數,2個是客戶端發來的,一個是服務端自己產生的,用着三個隨機數並結合對稱加密算法生成“會話密碼”
-
生成編碼變更通知、服務端握手結束通知
-
使用商定好的HASH算法對會話密碼、編碼變更通知、握手結束通知計算摘要,然后使用自己的私鑰進行對摘要進行簽名,最后使用客戶端公鑰加密信息並發送給客戶端
-
-
瀏覽器解密,然后得到消息的HASH,如果與服務端發來的HASH一致,此時握手過程結束,之后所有的通信數據都使用得到的“會話密碼” 加密。
這里為什么在認證通過后的數據傳輸使用認證過程產生的隨機密碼呢?這是因為使用對稱加密解密性能要比非對稱的高,尤其是對服務端的CPU壓力比較小,但是如果使用一個長期固定的對稱密碼就很不安全而隨機生成的就會有一個如何告訴通信雙方且傳遞過程中不被竊取的問題所以就使用非對稱加密方式這樣不但保證了隨機密碼的安全同時也可以驗證服務端身份的真實性。
為什么會產生這么多隨機數呢?為了避免計算機上產生的隨機數不是真的隨機數,所以雙方都產生隨機數然后使用大家的隨機數來生成密碼。