Https 入門理解

前言

一直對Https的原理只知其一;不知其二,只知道Https比Http協議更安全,可是爲何更安全呢?以及怎麼具體去部署一個Https呢?都是迷糊狀態,經過參考以下文章,對Https有一個入門理解(參考文章以及我的的看法)。javascript

參考資源:html

  1. 圖解HTTPS基本原理
  2. HTTPS證書生成原理和部署細節
  3. openssl命令目錄

首先放一張圖解HTTPS基本原理文章中的圖(加了我的的理解註釋):java

咱們後面會針對這個圖進行一步步的分析。node

下面咱們針對如下兩個主題來理解Https:git

  1. 在本地部署https 服務(實踐)
  2. 分析https(原理)

本地部署https

咱們須要理解https, 那咱們若是隻是針對原理來理解,相信不少環節都串聯不起來,看完後最終仍是一頭霧水。 因此咱們須要先實踐下Https究竟是個什麼東西, 到底該怎麼部署一個https服務。 參考文章: HTTPS證書生成原理和部署細節算法

生成CA機構

正常的咱們要運行一個Https, 須要向一個CA數字證書認證中心去申請一個咱們的CA證書。可是咱們只是想測試一下Https, 並不可能真的去一個合法的CA機構去申請一個證書,因此咱們可使用自簽名 來構建本身的CA機構, 也就是一個能夠給本身的服務器頒發證書的機構。shell

下面咱們來看怎麼生成一個本身的CA機構。瀏覽器

  1. 生成CA私鑰
openssl genrsa -out ca.key 1024
複製代碼

上面的ca.key就是CA機構的私鑰文件 關於openssl命令的使用方式能夠參考:openssl命令目錄安全

  1. 根據CA私鑰生成一個CA證書
# a.根據私鑰ca.key生成一個新的證書請求文件。其中"-new"表示新生成一個新的證書請求文件,
# "-key"指定私鑰文件,"-out"指定輸出文件,此處輸出文件即爲證書請求文件。
openssl req -new -key ca.key -out ca.csr
# x509 表示自簽署證書,可用於自建根CA時。
openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt
# 上面兩個步驟能夠合併爲: openssl req -x509 -key ca.key -in ca.csr -out ca.crt -days 365
複製代碼

在上面第二步的時候,會有以下的指引:bash

➜  keys  openssl req -new -key ca.key -out ca.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:Zhejiang
Locality Name (eg, city) []:Hangzhou
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My CA
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:localhost
Email Address []:
複製代碼

注意:咱們的服務器在向CA申請證書的時候,也會有如上的指引提示, Organization Name (eg, company) [Internet Widgits Pty Ltd] 的值不能同樣, 咱們能夠給CA機構設置值爲My CA, 咱們服務器在申請證書的時候設置的值爲My CA Server.

經過上面兩個步驟,咱們已經建立了自簽名機構。

咱們已經有了CA機構,如今咱們須要給咱們的服務向CA機構申請一個CA證書

申請CA證書

咱們在給咱們的服務申請CA證書的時候, 咱們首先須要給咱們本身的服務建立兩個鑰匙:公鑰私鑰

生成步驟以下:

  1. 生成私鑰
openssl genrsa -out server.key 1024
複製代碼
  1. 生成公鑰
openssl rsa -in server.key -pubout -out server.pem
複製代碼

上面生成了兩個文件: server.keyserver.pem, 咱們在生成公鑰的時候,是根據私鑰生成的。

咱們已經生成了公鑰和私鑰了,咱們如今須要向CA機構申請證書了, 能夠經過以下的腳本生成:

# 服務器端須要向 CA 機構申請簽名證書,在申請簽名證書以前依然是建立本身的 CSR 文件
openssl req -new -key server.key -out server.csr
# 向本身的 CA 機構申請證書,簽名過程須要 CA 的證書和私鑰參與,最終頒發一個帶有 CA 簽名的證書
openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
複製代碼

上面的server.crt就是咱們服務向CA申請的證書。

咱們能夠分析上面的腳本得:

  1. 在向CA申請證書的時候,咱們須要提供咱們服務的公鑰(server.key)
  2. 可是上面卻沒有提供私鑰(server.key)

總結:

  1. CA機構是保存了咱們的公鑰信息
  2. 咱們服務的私鑰信息,只有咱們的服務本身知道,其餘人誰也不知道。

在上面咱們已經準備好了自前面CA機構 ,已經咱們服務生成了公鑰,私鑰,以及向CA申請到了證書了,下面咱們就來看搭建Https服務了。

搭建https服務

咱們經過Nodejs 來搭建一個https服務,其腳本以下(咱們須要將上面生成的文件都放在咱們項目的keys目錄下):

// file http-server.js
var https = require('https');
var fs = require('fs');

var options = {
  key: fs.readFileSync('./keys/server.key'),// 服務器端私鑰
  cert: fs.readFileSync('./keys/server.crt')  
};

https.createServer(options, function(req, res) {
  res.writeHead(200);
  res.end('hello world 8000');
}).listen(8000, () => {
  console.log(`服務器啓動:localhost:8000`)
});
複製代碼

接下來咱們能夠經過node http-server.js來啓動咱們的服務了,咱們能夠在瀏覽器打開https://localhost:8000/

咱們能夠看到以下的效果:

看到上面的效果表面咱們的https服務搭建成功了,之因此瀏覽器顯示不安全,是由於瀏覽器只承認其內置的CA證書, 但這不影響咱們學習。

咱們點擊上面的證書,而後查看Certification Path 選項:

發現根證書不被信任,那咱們怎麼可讓瀏覽器信任咱們的自簽名CA呢, 我麼能夠按照以下操做:

  1. 按以下圖選擇網站設置:
  2. 選擇隱私和安全性,而後選擇管理證書:

  1. 選擇"Trusted Root Certification Authoritities"(信任的根證書機構), 而後選擇Import(導入),選擇咱們上面步驟生存的ca.crt 文件,進行安裝。安裝完成後,咱們能夠再次查看咱們的證書:

發現咱們的證書已經被瀏覽器信任了.

分析https(原理)

上面咱們已經簡單搭建了一個自簽名的https服務,咱們已經已經知道一些基本名詞: 私鑰,公鑰,CA,申請CA證書。下面咱們就根據上面咱們貼的圖片來解釋https運行的基本原理。

①:通常【客戶端】首先發起請求,例如請求網站https://www.thinktxt.com/, 生成一個隨機數(RandomC),攜帶支持的TLS版本、加密算法等信息發送至【服務端】

②:【服務端】收到請求, 返回證書、一個隨機數( RandomS)、 協商加密算法。這個時候,【服務端】已經保存了兩個隨機數: RandomCRandomS. 服務器端這個時候發送給客戶端的 RandomS是未加密的明文。

③:【客戶端】拿到證書後開始進行校驗,驗證其合法性。

客戶端經過本地瀏覽器或操做系統內置的權威第三方認證機構的CA證書進行驗證,一個證書包含域名、證書編號、公鑰、有效期等信息(這裏是指瀏覽器內置的CA機構,已經保存了咱們服務的證書的相關信息).

證書編號是在服務器管理員經過第三方證書機構申請證書的時候,第三方機構用他們的私鑰對證書編號進行加密存入證書,

上面一句話能夠根據咱們上面申請CA證書的裏的步驟進行理解:

# 服務器端須要向 CA 機構申請簽名證書,在申請簽名證書以前依然是建立本身的 CSR 文件
openssl req -new -key server.key -out server.csr
# 向本身的 CA 機構申請證書,簽名過程須要 CA 的證書和私鑰參與,最終頒發一個帶有 CA 簽名的證書
openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
複製代碼

證書編號: 能夠理解我上面腳本生成的server.crt的編號。 在上面的腳本中,用到的ca.key文件, 這個文件就是CA的私鑰

根據編號生成方法生成證書編號證書自己攜帶了生成證書編號的方法),

CA證書公鑰解密得出的證書編號進行對比,驗證不經過或者證書過時等狀況就提示存在風險(瀏覽器的紅色警告),驗證經過則進行下一步。

這裏是指咱們瀏覽器內置的CA保存咱們服務的CA證書的編號,可是經過ca.key私鑰加密過的, 咱們在驗證證書編號是否合法的時候,咱們再經過瀏覽器內置的CA的公鑰 對CA裏面保存的編號進行解密,用解密後的證書編號和服務器返回來的證書編號進行匹配。

④:【客戶端】生成一個隨機數(PreMaster Key),此時已經有第三個隨機數了,根據三個隨機數(RandomC、RandomS、PreMaster Key)按照雙方約定的算法生成用於後面會話的同一把的「會話密鑰」。

可是這個時候生成的「會話密鑰」 知識在客戶端生成保存起來,服務器這個時候仍是沒有第三個隨機數PreMaster Key, 服務器要想生成相同的「會話密鑰」, 則必須同時也知曉一樣的三個隨機數,因此如今的問題就是怎麼將第三個隨機數PreMaster Key傳給服務器。

⑤:【客戶端】將隨機數(PreMaster Key)經過公鑰加密後發送至【服務端】(這個步驟只是傳遞了加密後的隨機數PreMaster Key, 會話密鑰並無發送到服務端,由於須要服務端根據只有本身知道的私鑰去解密PreMaster Key, 而後生成對應的會話密鑰 )。

  1. 在這裏的公鑰 就是咱們服務端申請的CA證書裏面的內置的公鑰,也就是咱們服務器在申請CA證書時候生成的公鑰。經過公鑰加密的數據,只有對應的私鑰才能解密, 而這個私鑰只有咱們的服務端才知道,即便是CA機構都不知道的
  1. 咱們在①② 中傳遞的隨機數RandomC、RandomS 都是明文傳遞的,這裏爲何須要加密呢?由於咱們已經明文傳遞了兩個隨機數,若是第三個隨機數也明文傳遞, 那都是能夠被第三方攔截處理的。

⑥:【服務端】收到密文後用私鑰進行解密,獲得隨機數(PreMaster Key),此時服務端也擁有了三個隨機數,根據三個隨機數按照事先約定的加密算法生成用於後面會話的同一把的「會話密鑰」。

此時在服務端生成的會話密鑰 和④ 中瀏覽器生成的會話密鑰是同樣的啦。

⑦:【服務端】計算此前全部內容的握手消息hash值,並用「會話密鑰」加密後發送至客戶端用於驗證。

這個會話密鑰是瀏覽器和服務端根據三個隨機數生成的,並無經過網絡傳遞,第三方是獲取不到這個值的,而後經過會話密鑰加密數據傳遞給客戶端(其實這個時候能夠算是對稱加密了,由於瀏覽器和客戶端都已經知道密鑰了)

在⑦計算全部的內容的握手消息的hash 值, 並用【會話密鑰】加密後發送給客戶端。

⑧:【客戶端】解密並計算握手消息的hash值,若是與服務端發來的hash一致,此時握手過程結束。

  1. 客戶端根據本身在④生成的會話密鑰解密收到的消息
  2. 客戶端從新計算全部握手消息的hash值
  3. 將解密後的hash 和本身計算的hash 進行判斷,若是同樣,則算是真正的驗證經過了,能夠進行正常通訊了

⑨:驗證經過後,開始正常的加密通訊。

開始正常的進行通訊了,通訊內容會用會話密鑰和以前協商好的加密算法進行加密了。

總結:

  1. 服務端的私鑰 只要服務端知道,其餘人都不知道
  2. CA證書的校驗,是由於客戶端(瀏覽器)內置了全部的承認的CA證書,由於CA證書是客戶端(瀏覽器)內置的,因此不須要出如今網絡請求,也就不會出現第三方劫持的狀況,因此達到了安全傳輸保障
  3. CA證書中攜帶了服務端的公鑰, 用公鑰加密的數據,只有私鑰才能解密,也就是隻有服務端才能正確解密
  4. 會話密鑰是客戶端和服務端生成的,不在網絡請求中傳輸,因此會話密鑰是安全的
相關文章
相關標籤/搜索