HTTP通訊協議

程式人生-vincent發表於2020-11-17

首先,我們得知道應用層是 OSI 七層網路模型的第七層,不同型別的網路應用有不同的通訊規則,因此應用層協議是多種多樣的,比如 DNS、FTP、Telnet、SMTP、HTTP、 等協議都
是用於解決其各自的一類問題

http 通訊協議的基本原理

http 協議在遠端通訊場景中的應用還是挺廣泛的,包括現在主流的微服務架構的通訊都是基於 http 協議

一次HTTP請求的通訊流程

在瀏覽器上輸入一個網址後,瀏覽器是如何展示目標網址的內容的?內容是從哪裡來的呢?

DNS: (Domain Name System)服務是和 HTTP 協議一樣位於應用層的協議。它提供域名到 IP 地址之間的解析服務, 使用者通常使用主機名或域名來訪問對方的計算機,而不是直接通過 IP 地址訪問

因為與 IP 地址的一組純數字相比,用字母配合數字的表示形式來指定計算機名更符合人類的記憶習慣,但要讓計算機去理解名稱,相對而言就變得困難了。因為計算機更擅長處理一長串數字。為了解決上述的問題,DNS 服務應運而生。DNS 協議提供通過域名查詢 IP 地址,或逆向從IP 地址反查域名的服務

HTTP 通訊協議的組成

我們已經得知了 HTTP 協議的工作過程,同時我們也應該知道 HTTP 協議是基於應用層的協議,並且在傳輸層使用的 TCP 的可靠性通訊協議。既然是協議,那麼就應該符合協議的定義:協議是兩個需要通過網路通訊的程式達成的一種約定,它規定了報文的交換方式和包含的意義

請求URI 定位資源 

在瀏覽器中輸入一個地址,瀏覽器是如何根據地址去找到伺服器對應的資源並做返回的?以及這個地址包含了哪些有價值的資訊呢?

這就需要我們瞭解 URL (Uniform Resource Locator),統一資源定位符 ,用於描述一個網路上的資源,具體格式是 URI 用字串標識某一網際網路資源,而 URL 表示資源的地點(網際網路上所處的位置)。可見 URL 是 URI 的子集

http://www.vincent.com:80/java/index.html?name=vincent#head

schema://host[:port#]/path/.../?[url-params]#[ query-string]

scheme 指定應用層使用的協議(例如:http, https, ftp)
host       HTTP 伺服器的 IP 地址或者域名
port#      HTTP 伺服器的預設埠是 80,這種情況下埠號可以省略。如果使用了別的埠,必須指明,例如 http://www.cnblogs.com:8080/
path       訪問資源的路徑
query-string 查詢字串
# 片段識別符號(使用片段識別符號通常可標記出已獲取資源中的子資源(文件內的某個位置))

通過這個 url 地址,我們就可以讀到,當前使用者要使用 http 協議訪問指定伺服器上對應程式中的資源,並且攜帶了請求引數

MIME Type

伺服器根據使用者請求的資源找到對應的檔案以後,會返回一個資源給到客戶端瀏覽器,瀏覽器會對這個資源解析並且渲染。但是伺服器上的資源型別有很多,比如圖片型別、視訊型別、
Js、Css、文字等。瀏覽器如何識別當前型別做不同的渲染呢?

MIME Type:是描述訊息內容型別的因特網標準,常見的幾種型別:

  • 文字檔案:text/html,text/plain,text/css,application/xhtml+xml,application/xml
  • 圖片檔案:image/jpeg,image/gif,image/png.
  • 視訊檔案:video/mpeg,video/quicktime

可以通過兩種方式來設定檔案的渲染型別,第一種是 Accept,第二種是 Content-Type 

Accept: 表示客戶端希望接受的資料型別,即告訴伺服器我需要什麼媒體型別的資料,此時伺服器應該根據 Accept 請求頭生產指定媒體型別的資料

Content-Type: 表示傳送端傳送的實體資料型別 , 比如我們應該寫過類似的:resposne.setContentType(“application/json;charset=utf-8”)的程式碼,表示服務端返回的資料格式是 json

如果 Accept 和 Content-Type 不一致,假如說 Accept 要接收的型別是 image/gif,但是服務端返回的資料是 text/html,那麼瀏覽器將會無法解析

如果使用者訪問一個不存在的地址呢?

如果使用者訪問的地址沒問題,或者伺服器也能正常解析及處理當前使用者的請求,那就能夠返回正確的資訊給到客戶端。但是如果使用者訪問的地址有問題,或者服務端在解析使用者請求以
及處理請求邏輯時出現問題,怎麼辦呢?瀏覽器應該怎麼告訴使用者當前是處理失敗的呢
?因此這裡就涉及到一個狀態碼的概念

狀態碼的職責是當客戶端向服務端傳送請求時,描述服務端返回的請求處理結果,通過狀態碼,瀏覽器可以知道伺服器是正常處理請求還是出現了錯誤

狀態碼類別原因短語
1XXInformational(資訊性狀態碼)接收的請求正在處理
2XXSuccess(成功狀態碼)請求正常處理完畢
3XXRedirection(重定向狀態碼)需要進行附加操作以完成請求
4XXClient Error(客戶端錯誤狀態碼)伺服器無法處理請求
5XXServer Error(伺服器錯誤狀態碼)伺服器處理請求出錯

大家見得比較多的錯誤碼:

200:一切正常
301:永久重定向
404:請求資源不存在
500:服務端內部錯誤

有了狀態碼,在使用者訪問某個網站出現非正常狀態時,瀏覽器就可以很友好的提示使用者

告訴伺服器端當前請求的意圖

有了 url,mimetype、狀態碼, 能夠基本滿足使用者的需求,但是,很多時候一個網站不單純只是不斷從服務端獲取資源並做渲染,可能還需要做一些資料的提交、刪除等功能。所以瀏覽器定義了 8 種方法來表示對於不同請求的操作方式,當然最常用的還是 Get 和 Post

  • GET

一般是用於客戶端傳送一個 URI 地址去獲取服務端的資源(一般用於查詢操作),Get不支援的傳輸資料有限制,具體限制由瀏覽器決定

  • POST

一般使用者客戶端傳輸一個實體給到服務端,讓服務端去儲存(一般用於建立操作)

  • PUT

向伺服器傳送資料,一般用於更新資料的操作

  • DELETE

客戶端發起一個 Delete 請求要求服務端把某個資料刪除(一般用於刪除操作)

  • HEAD

獲得報文首部

  • OPTIONS

詢問支援的方法

  • TRACE

追蹤路徑、

  • CONNECT

用隧道協議連線代理

在 REST 架構風格中,有嚴格規定對於不同的請求型別要設定合適的請求方法。也是避免出現因為亂用導致混亂的問題

提到了 REST 架構,現在很多人都在寫 REST,有沒有人能夠明白為什麼要定義 REST 這個架構風格?

1. 隨著服務化架構的普及,http 協議的使用頻率越來越高

2. 很多人在錯誤的使用 http 協議定義介面,比如各種各樣的命名,什麼 getUserInfoById,deleteById 之類的、有狀態和無狀態請求混用

3. 對於 http 協議本身提供的規則並沒有很好的利用

所以,為了更好的解決這些問題,乾脆就定義一套規則,這套規則並沒有引入新的東西,無非就是對 http 協議本身的使用做了一些約束,比如說

1. REST 是面向資源,每一個 URI 代表一個資源

2. 強調無狀態化,伺服器端不能儲存來自某個客戶的某個請求中的資訊,並在該客戶的其他請求中使用

3. 強調 URL 暴露資源時,不要在 URI 中出現動詞

4. 合理的利用 http 狀態碼、請求方法

因此大家在參照這種標準去使用REST風格時,要明白你遵循的是什麼以及要解決什麼問題

http協議的完整組成

http 協議包含兩個報文,一個是請求報文,一個是響應報文

請求報文

請求報文格式包含三個部分(起始行、首部欄位、主體)

響應報文

響應的報文格式也是一樣,分為三部分

如果傳輸的檔案過大怎麼辦?

伺服器上返回的資原始檔比較大,比如有些 js 檔案大小可能就有幾兆。檔案過大就會影響傳輸的效率,同時也會帶來頻寬的消耗。怎麼辦呢?

1、常見的手段是,對檔案進行壓縮,減少檔案大小

那壓縮和解壓縮的流程怎麼實現呢?

首先服務端需要能支援檔案的壓縮功能,其次瀏覽器能夠針對被壓縮的檔案進行解壓縮。瀏覽器可以指定 Accept-Encoding 來高速伺服器我當前支援的編碼型別Accept-Encoding:gzip,deflate,那服務端會根據支援的編碼型別,選擇合適的型別進行壓縮。常見的編碼方式有:gzip/deflate

2、分割傳輸

在傳輸大容量資料時,通過把資料分割成多塊,能夠讓瀏覽器逐步顯示頁面。這種把實體主體分塊的功能稱為分塊傳輸編碼(Chunked Transfer Coding)

每次請求都要建立連線嗎?

在 HTTP/1.1 中改用了持久連線,就是在一次連線建立之後,只要客戶端或者服務端沒有明確提出斷開連線,那麼這個 tcp 連線會一直保持連線狀態

持久連線的一個最大的好處是:大大減少了連線的建立以及關閉時延

HTTP1.1 中有一個 Transport 段。會攜帶一個 Connection:Keep-Alive,表示希望將此條連線作為持久連線

HTTP/1.1 持久連線在預設情況下是啟用的,除非特別指明,否則 HTTP/1.1 假定所有的連線都是持久的,要在事務處理結束之後將連線關閉,HTTP/1.1 應用程式必須向報文中顯示地新增
一個 Connection:close 

HTTP1.1 客戶端載入在收到響應後,除非響應中包含了 Connection:close ,不然 HTTP/1.1連線就仍然維持在開啟狀態。但是,客戶端和伺服器仍然可以隨時關閉空閒的連線。不傳送Connection:close 並不意味這伺服器承諾永遠將連線保持在開啟狀態

管道化連線: http/1.1 允許在持久連線上使用請求管道。以前傳送請求後需等待並收到響應,才能傳送下一個請求。管道化技術出現後,不用等待響應亦可直接傳送下一個請求。這樣就能夠做到同時並行傳送多個請求,而不需要一個接一個地等待響應了

Http 協議的特點

Http無狀態協議

HTTP 協議是無狀態的,什麼是無狀態呢?

就是說 HTTP 協議本身不會對請求和響應之間的通訊狀態做儲存,但是現在的應用都是有狀態的,如果是無狀態,那這些應用基本沒人用,你想想,訪問一個電商網站,先登入,然後去選購商品,當點選一個商品加入購物車以後又提示你登入。這種使用者體驗根本不會有人去使用。那我們是如何實現帶狀態的協議呢?

客戶端支援的 cookie

Http 協議中引入了 cookie 技術,用來解決 http 協議無狀態的問題。通過在請求和響應報文中寫入 Cookie 資訊來控制客戶端的狀態;Cookie 會根據從伺服器端傳送的響應報文內的一個叫做 Set-Cookie 的首部欄位資訊,通知客戶端儲存 Cookie。當下次客戶端再往該伺服器傳送請求時,客戶端會自動在請求報文中加入 Cookie 值後傳送出去

服務端支援的  session

服務端是通過什麼方式來儲存狀態的呢?

在基於 tomcat 這類的 jsp/servlet 容器中,會提供session 這樣的機制來儲存服務端的物件狀態,伺服器使用一種類似於雜湊表的結構來儲存資訊,當程式需要為某個客戶端的請求建立一個 session 的時候,伺服器首先檢查這個客戶端的請求是否包含了一個 session 標識- session id;如果已包含一個 session id 則說明以前已經為客戶端建立過 session,伺服器就按照 session id 把這個 session 檢索出來使用(如果檢索不到,會新建一個);如果客戶端請求不包含 sessionid,則為此客戶端建立一個 session 並且生成一個與此 session相關聯的 session id, session id 的值是一個既不會重複,又不容易被找到規律的仿造字串,這個 session id 將會返回給客戶端儲存

Tomcat  實現 session 的程式碼邏輯分析

以 HttpServletRequest#getSession() 作為切入點,對 Session 的建立過程進行分析我 們 的 應 用 程 序 拿 到 的 HttpServletRequest  是org.apache.catalina.connector.RequestFacade(除非某些 Filter 進行了特殊處理),它是org.apache.catalina.connector.Request 的門面模式。首先,會判斷 Request 物件中是否存在 Session,如果存在並且未失效則直接返回

如果不存在 Session,則嘗試根據 requestedSessionId 查詢 Session,如果存在 Session 的話則直接返回,如果不存在的話,則建立新的 Session,並且把 sessionId 新增到 Cookie 中,
後續的請求便會攜帶該 Cookie,這樣便可以根據 Cookie 中的 sessionId 找到原來建立的Session 了

Https 協議基本分析

由於 HTTP 協議在通訊過程中,是基於明文通訊,並且底層是基於 TCP/IP 協議進行通訊,那麼按照 TCP/IP 協議族的工作機制,通訊內容在所有的通訊線路上都有可能遭到攔截和竊取。
竊取這個過程其實很簡單,通過抓包工具 Wireshark 就可以截獲請求和響應的內容

https安全傳輸協議

由於 HTTP 協議通訊的不安全性,所以人們為了防止資訊在傳輸過程中遭到洩漏或者篡改,就想出來對傳輸通道進行加密的方式 https

https 是一種加密的超文字傳輸協議,它與 HTTP 在協議差異在於對資料傳輸的過程中,https對資料做了完全加密。由於 http 協議或者 https 協議都是處於 TCP 傳輸層之上,同時網路協
議又是一個分層的結構,所以在 tcp 協議層之上增加了一層 SSL(Secure Socket Layer,安全層)或者 TLS(Transport Layer Security) 安全層傳輸協議組合使用用於構造加密通道;

Ssl 是 netscape 公司設計的(Secure sockets layer),後來網際網路標準化組織 ISOC 接替了NETScape 公司,釋出了 SSL 的升級版 TLS。接著 TLS 的版本又進行了多次升級; 實際上我
們現在的 HTTPS 都是用的 TLS 協議
,但是由於 SSL 出現的時間比較早,並且依舊被現在瀏覽器所支援,因此 SSL 依然是 HTTPS 的代名詞

逆向推導 https 的設計過程

從第一個訊息開始

客戶端 A 向服務端 B 傳送一條訊息,這個訊息可能會被攔截以及篡改,我們如何做到 A 傳送給 B 的資料包,及時被攔截了,也沒辦法得知訊息內容並且也不能檢視呢?

利用對稱加密

要做到訊息不能被第三方檢視以及篡改,那麼第一想法就是對內容進行加密,同時,該訊息還需要能被服務端進行解密。所以我們可以使用對稱加密演算法來實現,金鑰 S 扮演著加密和
解密的角色。在金鑰 S 不公開的情況下,就可以保證安全性?

沒那麼簡單

在網際網路世界,通訊不會這麼簡單,也許是這樣

會存在多個客戶端和服務端產生連線,而這個客戶端也許是一個潛伏者,如果他也有對稱金鑰 S,那相當於上面的方案是不可行的?如果服務端和每個客戶端通訊的時候使用不同的加密演算法呢?

似乎能夠完美解決問題,然後?金鑰如何分配呢?也就是服務端怎麼告訴客戶端該使用那種對稱加密演算法呢?解決辦法似乎只能通過建立會話以後進行協商了?

協商過程又是不安全的

協商過程,意味著又是基於一個網路傳輸的情況下去動態分配金鑰,可是這個協商過程又是不安全的,怎麼破?

非對稱加密出馬

非對稱加密演算法的特點是:私鑰加密後的密文,只要有公鑰,都能解密,但是公鑰加密後的密文,只有私鑰可以解密。私鑰只有一個人有,而公鑰可以發給所有人

這樣就可以保證 A/B 向伺服器端方向傳送的訊息是安全的。似乎我們通過非對稱加密演算法解決了金鑰的協商的問題?但是

公鑰怎麼拿?

使用非對稱加密演算法,那麼如何讓 A、B 客戶端安全地持有公鑰?

逐步思考,有兩種我們能想到的方案:

1. 伺服器端將公鑰傳送給每一個客戶端

2. 伺服器端將公鑰放到一個遠端伺服器,客戶端可以請求到 (多了一次請求,還得解決公鑰放置問題)

方案一似乎不可行,因為,傳輸過程又是不安全的?公鑰可能會被調包

引入第三方機構

引入一個可信任的第三者是一個好的方案,服務端把需要傳遞給客戶端的公鑰,通過第三方機構提供的私鑰對公鑰內容進行加密後,再傳遞給客戶端? 通過第三方機構私鑰對服務端公鑰加密以後的內容,就是一個簡陋版本的“數字證照”。這個幀數中包含【伺服器公鑰】

客戶端拿到這個證照以後,因為證照是第三方機構使用私鑰加密的。客戶端必須要有第三方機構提供的公鑰才能解密證照。這塊又涉及到第三方機構的公鑰怎麼傳輸?(假設是先內建在系統中)以及還有一個問題,第三方機構頒發的證照是面向所有使用者,不會只針對一家發放

如果不法分子也拿到證照?

如果不法分子也申請了證照,那它可以對證照進行調包。客戶端在這種情況下是無法分辨出收到的是你的證照,還是中間人的。因為不論是中間人的、還是你的證照都能使用第三方機構的公鑰進行解密

驗證證照的有效性

事情發展到現在,問題演變成了,客戶端如何識別證照的真偽?在現實生活中,要驗證一個東西的真偽,絕大部分都是基於編號去驗證(比如大學畢業證照,比如買的數碼產品是否是
山寨),我之前講過,計算機領域的解決方案都是人為去實現的,所以在這裡,解決方案也是一樣,如果給這個數字證照新增一個證照編號?是不是就能達到目的呢?

證照上寫了如何根據證照的內容生成證照編號。客戶端拿到證照後根據證照上的方法自己生成一個證照編號,如果生成的證照編號與證照上的證照編號相同,那麼說明這個證照是真實
。 這塊有點類似於 md5 的驗證,我們下載一個軟體包,都會提供一個 md5 的值,我們可以拿到這個軟體包以後通過一個第三方軟體去生成一個 md5 值去做比較,是不是一樣如果
一樣表示這個軟體包沒被篡改過

對服務端的資料進行 MD5 演算法得到一個MD5 的值,生成證照編號,使用第三方機構的私鑰對這個證照編號進行加密,並且會在證照中新增證照編號的生成演算法

瀏覽器內建的 CA 公鑰可以解密服務端 CA 私鑰加密的證照,通過瀏覽器內建的 CA 證照的證照編號演算法對服務端返回的證照編號進行驗籤

第三方機構的公鑰證照存哪裡?

瀏覽器和作業系統都會維護一個權威的第三方機構列表(包括他們的公鑰),因為客戶端接收到的證照中會些頒發機構,客戶端就根據這個辦法機構的值在本地找到響應的公鑰

證照就是 HTTPS 中的數字證照,證照編號就是數字簽名,而第三方機構就是數字證照的簽發機構(CA)

Https 原理分析

HTTPS  證照的申請過程

1、伺服器上生成 CSR 檔案(證照申請檔案,內容包括證照公鑰、使用的 Hash 簽名演算法、申請的域名、公司名稱、職位等資訊)

2、把 CSR 檔案和其他可能的證件上傳到 CA 認證機構,CA 機構收到證照申請之後,使用申請中的 Hash 演算法,對部分內容進行摘要,然後使用 CA 機構自己的私鑰對這段摘要資訊進行
簽名(相當於證照的唯一編號)

3、然後 CA 機構把簽名過的證照通過郵件形式傳送到申請者手中
4、申請者收到證照之後部署到自己的 web 伺服器中

客戶端請求互動流程

1. 客戶端發起請求(Client Hello 包)

  • 三次握手,建立 TCP 連線
  • 支援的協議版本(TLS/SSL)
  • 客戶端生成的隨機數 client.random,後續用於生成“對話金鑰”
  • 客戶端支援的加密演算法
  • sessionid,用於保持同一個會話( 如果客戶端與伺服器費盡周折建立了一個 HTTPS 連結,剛建完就斷了,也太可惜 )

2. 服務端收到請求,然後響應(Server Hello)

  • 確認加密通道協議版本
  • 服務端生成的隨機數 server.random,後續用於生成“對話金鑰”
  • 確認使用的加密演算法(用於後續的握手訊息進行簽名防止篡改)
  • 伺服器證照(CA 機構頒發給服務端的證照)

3. 客戶端收到證照進行驗證

  • 驗證證照是否是上級 CA 簽發的, 在驗證證照的時候,瀏覽器會呼叫系統的證照管理器介面對證照路徑中的所有證照一級一級的進行驗證,只有路徑中所有的證照都是受信的,整個驗證的結果才是受信
  • 服務端返回的證照中會包含證照的有效期,可以通過失效日期來驗證 證照是否過期
  • 驗證證照是否被吊銷了
  • 前面我們知道 CA 機構在簽發證照的時候,都會使用自己的私鑰對證照進行簽名證照裡的簽名演算法欄位 sha256RSA 表示 CA 機構使用 sha256 對證照進行摘要,然後使用 RSA 演算法對摘要進行私鑰簽名,而我們也知道 RSA 演算法中,使用私鑰簽名之後,只有公鑰才能進行驗籤。
  • 瀏覽器使用內建在作業系統上的 CA 機構的公鑰對伺服器的證照進行驗籤。確定這個證照是不是由正規的機構頒發。驗籤之後得知 CA 機構使用 sha256 進行證照摘要,然後客戶端再使用 sha256 對證照內容進行一次摘要,如果得到的值和服務端返回的證照驗籤之後的摘要相同,表示證照沒有被修改過
  • 驗證通過後,就會顯示綠色的安全字樣
  • 客戶端生成隨機數,驗證通過之後,客戶端會生成一個隨機數 pre-master secret,客戶端根據之前的:Client.random + sever.random + pre-master 生成對稱金鑰然後使用證照中的公鑰進行加密,同時利用前面協商好的 HASH 演算法,把握手訊息取 HASH 值,然後用 隨機數加密 “握手訊息+握手訊息 HASH 值(簽名)” 並一起傳送給服務端 ( 在這裡之所以要取握手訊息的 HASH 值,主要是把握手訊息做一個簽名,用於驗證握手訊息在傳輸過程中沒有被篡改過

4. 服務端接收隨機數

  • 服務端收到客戶端的加密資料以後,用自己的私鑰對密文進行解密。然後得到client.random/server.random/pre-master secret, HASH 值,並與傳過來的 HASH 值做對比確認是否一致
  • 然後用隨機密碼加密一段握手訊息(握手訊息+握手訊息的 HASH 值 )給客戶端

5. 客戶端接收訊息

  • 客戶端用隨機數解密並計算握手訊息的 HASH,如果與服務端發來的 HASH 一致,此時握手過程結束
  • 之 後 所 有 的 通 信 數 據 將 由 之 前 交 互 過 程 中 生 成 的 pre master secret /client.random/server.random 通過演算法得出 session Key,作為後續互動過程中的對稱金鑰

https 應用實戰

基於 Nginx 配置一個 https 的證照。在生產環境中的 SSL 證照都需要通過第三方認證機構購買,分為專業版 OV 證照(瀏覽器位址列上不顯示企業名稱)和高階版 EV(可以顯示企業名稱)證照,證照所保護的域名數不同也會影響價格(比如只對 www 認證和通配*認證,價格是不一樣的),且不支援三級域名。代表證照過期或者無效,如果是黃色的話代表網站有部分連線使用的仍然是 http 協議。如果大家自己買了域名的話,可以在阿里雲上申請一個免費的證照來使用

為了演示證照的申請過程,直接使用 openssl,自己作為證照頒發機構來製作證照,但是這個證照是不受信任的,所以到時候演示的結果瀏覽器會提示證照不受信的錯誤

證照的申請過程

生成伺服器證照的申請檔案和私鑰檔案

在 nginx 的 conf 目錄下建立 cert 資料夾,在該資料夾中生成公私鑰

openssl req -nodes -newkey rsa:2048 -out myreq.csr -keyout privatekey.key

req:表示發出一個申請數字證照的請求
rsa:2048 表示加密演算法以及長度

out:輸出一個請求檔案
keyout:生成私鑰
myreq.csr :證照籤名請求,這個並不是一個證照,而是向權威機構獲取簽名證照的申請,它的主要內容是一個公鑰
privatekey.key: 與公鑰相匹配的私鑰

CSR(證照請求檔案),用來向 CA 機構申請的檔案,一般以 CSR 結尾,包含申請證照所需要的相關資訊,其中最重要的是域名,填寫的域名必須是你要 https 方式訪問的那個域名
一個是 KEY 檔案,這個檔案一定要儲存好,這個檔案就是對應 server 端的私鑰,這個資訊首先是重要,如果這個 KEY 檔案沒有儲存好,是無法找回的,因為 KEY 生成的過程不可逆,即
使填寫的過程都一樣,生成的 KEY 是不通的,具有隨機性

執行這個命令以後,需要輸入很多資訊

模擬 CA 機構製作 CA 機構證照

CA 機構有自己的公私鑰,CA 會使用自己的公私鑰對證照申請者提交的公鑰進行加密。所以為了模擬 CA 機構的工作流程,需要先建立一個 CA 的證照

openssl 的配置檔案:/etc/pki/tls/openssl.cnf

以下是 openssl CA 的預設配置,我們需要配置 CA 的證照,就需要在指定的目錄下建立對應的檔案

1. 建立所需要的檔案

touch /etc/pki/CA/index.txt 生成證照索引資料庫檔案
echo 01 > /etc/pki/CA/serial 指定第一個頒發證照的序列號,必須是兩位十六進位制數,99之後是 9A

2. CA 自簽證照-生成私鑰

cd /etc/pki/CA/
openssl genrsa -out /etc/pki/CA/private/cakey.pem 2048

3. 生成自簽名證照

openssl req -new -x509 –key /etc/pki/CA/private/cakey.pem -days 365 -out /etc/pki/CA/cacert.pem
提示輸入國家,省,市,公司名稱,部門名稱,CA 主機名(頒發者名稱)

4. 頒發證照

openssl ca -policy policy_anything -in myreq.csr -out mycert.crt -days 365
policy policy_anything: policy 引數允許簽名的 CA 和網站證照可以有不同的國家、地名等資訊
out: ca 頒發的證照檔案
days: 證照有效期

nginx 配置 https

在 nginx.conf 中配置 server 段, 將證照 mycert.pem 和私鑰 pem 新增到指定檔案中

server {
    listen 443 ssl;
    ssl on;
    ssl_certificate cert/mycert.crt;
    ssl_certificate_key cert/privatekey.key;
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout 5m;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    location / {
        root html;
        index index.html index.htm;
    }
}

為什麼證照一下是以 pem 結尾,一下又是以 crt 結尾,一下又是 key 結尾。到底是什麼意思?

其實,x.509 標準的證照,有兩種編碼格式,一種是 PEM、一種是 DER
但實際上我們在建立證照和私鑰的時候,並不一定要以 PEM 或者 DER 作為副檔名
比如證照的表示方式有:PEM、DER、CRT、CER
私鑰或者公鑰的表示形式:PEM、DER、KEY
只是對應的編碼格式不同而已

nginx  新增 https  支援

要給已經安裝好的 nginx 新增證照支援,需要按照以下步驟來進行:

1. 【/data/program/nginx/sbin/nginx -V】 檢視之前 nginx 編譯安裝了哪些模組,避免遺漏掉一些模組配置導致出現問題

2. 【cd /data/program/nginx-1.11】 進入之前下載的 nginx 原始碼包目錄中

3. 【 ./configure --prefix=/data/program/nginx --with-http_stub_status_module --with- http_ssl_module】 重新編譯,新增 ssl 模組支援

4. 【make】 執行 make 命令,千萬不能執行 make install,不然會把之前已經安裝的 nginx覆蓋掉

5. 【cp /data/program/nginx/sbin/nginx /data/program/nginx/sbin/nginx.bak】 備份原來的啟動指令碼

6. 【cp objs/nginx /data/program/nginx/sbin/】 替換 nginx 的二進位制指令碼

7. 【/data/program/nginx/sbin/nginx -V】再次驗證是否把需要的模組編譯進去了

相關文章