HTTPS = HTTP + SSL
HTTP協議是明文傳輸的,也就是說當數據包使用HTTP協議進行傳輸的時候,如果數據包中途被截下來了,那麼裏面的數據(明文)就會完全暴露。因此,如果數據包裏面存放着用戶的帳號和密碼,就可以認爲用戶的帳號和密碼已經泄漏了。
HTTPS協議則使用了SSL對數據進行加密,即使數據被攔截下來,如果沒有解密的密鑰,也無法得知用戶的數據。
RSA
RSA是一種非對稱加密的算法,所謂非對稱加密算法,就是用於加密解密的密鑰有兩個,即公鑰和私鑰,用公鑰加密過的數據,只有私鑰才能解密,用私鑰加密過的數據,只有公鑰才能解密。(對稱加密算法就是說用於加密解密的只有一個密鑰,密鑰既能加密數據,又能解密數據)
公鑰是可以公開的,別人知道也無所謂,私鑰則要存儲在安全的地方,不能泄漏。
考慮一下在客戶端與服務器之間RSA的應用場景。
- 客戶端向服務器發送數據
- 因爲服務器的公鑰是公開的,所以客戶端很容易就能獲取得到服務器的公鑰。客戶端利用服務器的公鑰加密數據,這些數據只有存儲在服務器的私鑰才能解密。
- 服務器向客戶端發送數據
- 服務器在向客戶端發送數據的時候,除了用私鑰加密以外,還要生成一個數字簽名。
- 什麼是數字簽名?服務器會使用hash函數對向客戶端發送的數據生成一個摘要(digest),然後用服務器的私鑰加密這一個digest,得到的就是數字簽名了。
- 當客戶端拿到服務器發送的數據後,對數據使用相同的hash函數加密一遍,和用公鑰解密的digest進行對比,如果核對一致則說明中途傳輸的數據沒有被篡改。
- 考慮第三種情況,如何確保你拿到的服務器公鑰確實是正確的服務器的公鑰呢? 即有人將其他的服務器的公鑰給了客戶端,使客戶端誤以爲自己在跟正確的服務器進行交互。(攻擊者可以在代理服務器層攔截客戶端的請求,再重定向到自己的服務器)
- 這時候我們需要一個權威的第三方機構(CA)確認這一個公鑰確實是真實的服務器的公鑰,服務器將自己的公鑰和一些私人信息發給CA,CA用自己的私鑰將這些數據加密之後就是數字證書(SSL證書)。
- 當服務器向客戶端發送數據的時候,還附帶上從CA下載到本地的證書,客戶端拿到證書以後使用CA的公鑰進行解密,確認服務器的公鑰無誤。
客戶端與服務器最終交互流程如下:
RSA的運用場景:SSH
SSH遠程登錄主要有兩種登錄類型:口令登錄以及密鑰登錄。
- 口令登錄
- 客戶端首先發出登錄請求,服務器返回一個公鑰,客戶端使用公鑰對登錄密碼進行加密,傳輸給服務器後,服務器使用私鑰對登錄密碼解密然後覈對。
- 密鑰登錄
- 客戶端發出登錄請求之後,服務器隨機發送一段字符串,客戶端使用自己的私鑰加密之後返回給服務器,服務器使用存儲的客戶端的公鑰進行解密,解密成功則登錄成功。
有幾點SSH文件放置注意的地方:
- 客戶端存放服務器公鑰的地方在.ssh/known_hosts。
- 服務器存放客戶端公鑰的地方在.ssh/authorized_keys。
如果使用密鑰登錄可以使用ssh-copy-id命令,不過要注意權限問題。
SSL
SSL是基於非對稱加密的原理,在這之上還進行了對稱加密的數據傳輸。當傳送數據量過大的時候,客戶端和服務器之間互相商定了一個對話密鑰(session key),使用這個對話密鑰來進行對稱加密加快運算速度。
整個SSL的流程如下:
- 客戶端向服務器請求證書,驗證無誤後拿到服務器的公鑰
- 雙方協商生成一個session key
- 最後雙方採用session key進行加密通信
主要關注前兩步,即SSL的握手階段。
- Client Hello
- 客戶端向服務器發出一個隨機數,以及支持的傳輸協議以及加密算法 ,壓縮方法。
- Server Hello
- 服務器在確認支持客戶端的傳輸協議等要求後,發送服務器的證書,以及一個隨機數,安全需求更高的服務器會要求客戶端發送證書來證明客戶端的身份。
- 客戶端迴應
- 客戶端此時生成第三個隨機數(這一個隨機數被稱爲pre-master-key),向CA驗證服務器的證書以後拿到服務器的公鑰,使用公鑰加密第三個隨機數,並把加密後的第三個隨機數發送給服務器。
- 客戶端在本地利用之前與服務器商量好的加密方法,根據這三個隨機數生成一個對話密鑰(session key)用於兩端通信。
- 服務端迴應
- 服務端收到第三個隨機數後,計算出對話密鑰,至此,握手階段結束。接下來使用對話密鑰進行通信即可。
這裏參考這篇博客中的一張表示SSL運行機制的圖片:
SSL證書籤名申請(CSR)
在購買了SSL證書以後,需要把證書和域名綁定起來。一般的證書是隻能用在一個域名上,不過端口不限制。
如果希望子域名都能使用HTTPS可以考慮入手一個通配型的SSL證書,或者子域名個數不多的時候可以使用UCC類型的SSL證書。UCC類型的SSL證書是指一個證書可以加密指定數量的網站,在配置證書的時候往SAN裏面添加額外的域名即可。
在服務器端使用openssl命令生成一個csr爲後綴的文件(同時還有你的服務器私鑰key文件),然後上傳或者粘貼CSR文件內容至購買域名的網站:
openssl req -new -newkey rsa:2048 -nodes -keyout 您的域名.key -out 您的域名.csr
筆者購買的是GoDaddy的域名證書,該網站還提供了詳細的Nginx的CSR配置文件指導,傳送門如下:
生成 NGINX CSR(證書籤名申請)
在提交CSR文件後CA會確認你是否擁有對這個域名的所有權,Godaddy提供了兩種驗證方法:
首先,Godaddy會發送一封郵件,郵件裏包含了要顯示的指定內容。
第一種方法 ,如果沒有對域名的管理權,但是擁有域名映射到的服務器的所有權,將指定內容做成HTML文件,並上傳至域名映射的服務器的根目錄等待Godaddy確認。
第二種方法,如果擁有對域名的管理權,則在域名解析裏面添加TXT類型的DNS記錄,記錄值就爲指定內容,等待Godaddy確認。
可以通過以下命令來確認TXT記錄類型的DNS解析已經生效:
# 使用下面其中一條命令即可 dig -t TXT domain_name host -t TXT domain_name
如果對於DNS的記錄類型感到疑惑的話可以參考這篇博客:常用域名記錄解釋:A記錄、MX記錄、CNAME記錄、TXT記錄、AAAA記錄、NS記錄
域名所有權或者管理權驗證完畢之後,即可下載SSL證書。
筆者在Godaddy下載證書之後得到兩個證書(兩個crt文件),其中有一個帶有bundle命名的中間證書,需要把兩個證書串聯在一起得到一個最終證書。
$ cat first.crt bundle.crt > example.com.crt
Nginx配置HTTPS
非常簡單,只需要在監聽的端口上加上SSL配置就好了。
server {
listen 9999 ssl;
server_name example.com;
ssl on;
ssl_certificate /root/.ssl/example_com.crt;
ssl_certificate_key /root/.ssl/example_com.key;
}
參考資料: