1. 程式人生 > 其它 >Nginx配置ssl模組踩坑與過坑案例

Nginx配置ssl模組踩坑與過坑案例

前景提要

目前越來越多的產品開始採用HTTPS,而採用HTTPS就需要SSL證書,所以需要在nginx中使用ssl模組配置HTTPS的支援。本文就是nginx配置ssl模組中一個踩坑與過坑的案例。

HTTPS科普:

首先來科普下什麼是HTTPS?HTTPS (基於安全套接字層的超文字傳輸協議或者是HTTP over SSL)是一個Netscape開發的Web協議。可以這麼認為:HTTPS = HTTP + SSL。

超文字傳輸協議(HTTP)是一個用來通過網際網路傳輸和接收資訊的協議。HTTP使用請求/響應的過程,因此資訊可在伺服器間快速、輕鬆而且精確的進行傳輸,當我們在訪問web頁面時,採用的是不安全的HTTP協議。所以Netscape推出了HTTPS,也就是基於安全套接字層的HTTP協議

大多數情況下,HTTP和HTTPS是相同的,因為都是採用同一個基礎的協議,作為HTTP或HTTPS客戶端——瀏覽器,設立一個連線到Web伺服器指定的埠。當伺服器接收到請求,它會返回一個狀態碼以及訊息,這個迴應可能是請求資訊、或者指示某個錯誤傳送的錯誤資訊。系統使用統一資源定位器URI模式,因此資源可以被唯一指定。而HTTPS和HTTP唯一不同的只是一個協議頭(https)的說明,其他都是一樣的。下文列舉一下HTTP和HTTPS的不同之處:

HTTP 的 URL 以 http:// 開頭,而 HTTPS 的 URL 以 https:// 開頭
HTTP 是不安全的,而 HTTPS 是安全的
HTTP 標準埠是 80 ,而 HTTPS 的標準埠是 443
在 OSI 網路模型中,HTTP 工作於應用層,而 HTTPS 工作在傳輸層
HTTP 無需加密,而 HTTPS 對傳輸的資料進行加密
HTTP 無需證書,而 HTTPS 需要認證證書

簡而言之,在使用HTTPS連線時,伺服器要求有公鑰和簽名的證書。當使用 https 連線,伺服器響應初始連線,並提供它所支援的加密方法。作為迴應,客戶端選擇一個連線方法,並且客戶端和伺服器端交換證書驗證彼此身份。完成之後,在確保使用相同金鑰的情況下傳輸加密資訊,然後關閉連線。為了提供 https 連線支援,伺服器必須有一個公鑰證書,該證書包含經過證書機構認證的金鑰資訊,大部分證書都是通過第三方機構授權的,以保證證書是安全的。上文提到HTTPS = HTTP + SSL,那HTTP和SSL分別需要做的工作是這樣的:

HTTP包含如下動作:

瀏覽器開啟一個 TCP 連線
瀏覽器傳送 HTTP 請求到伺服器端
伺服器傳送 HTTP 迴應資訊到瀏覽器
TCP 連線關閉

SSL包含如下動作:

驗證伺服器端
允許客戶端和伺服器端選擇加密演算法和密碼,確保雙方都支援
驗證客戶端(可選)
使用公鑰加密技術來生成共享加密資料
建立一個加密的 SSL 連線
基於該 SSL 連線傳遞 HTTP 請求

nginx配置

當然,前面的都是鋪墊,本文的重點終於來了。就是如何生成SSL證書並配置nginx。這部分通常都是PE或者SA進行操作的,但是如果想在測試環境自己玩一玩的話,那麼攻略來了。

1. 生成證書

可以通過以下步驟生成一個簡單的證書:
首先,進入你想建立證書和私鑰的目錄,例如:
$ cd /home/appuser/nginx-1.4.7/conf
建立伺服器私鑰,命令會讓你輸入一個口令:
$ openssl genrsa -des3 -out cookie.key 1024
建立簽名請求的證書(CSR):
$ openssl req -new -key cookie.key -out cookie.csr
在載入SSL支援的Nginx並使用上述私鑰時除去必須的口令:
$ cp cookie.key cookie.key.org
$ openssl rsa -in cookie.key.org -out cookie.key

2. 配置nginx

最後標記證書使用上述私鑰和CSR:
$ openssl x509 -req -days 365 -in cookie.csr -signkey cookie.key -out cookie.crt
修改Nginx配置檔案,讓其包含新標記的證書和私鑰:
server {
    server_name YOUR_DOMAINNAME_HERE;
    listen 443;
    ssl on;
    ssl_certificate /usr/local/nginx/conf/server.crt;
    ssl_certificate_key /usr/local/nginx/conf/server.key;
}
重啟nginx

踩坑與過坑

本來以為這樣就可以萬事大吉了,但是在壓力提高以後,就會出現一些錯誤。去檢視nginx的錯誤日誌以及dmesg的報錯如下:

nginx報錯:

2016/12/26 19:37:48 [alert] 27592#0: worker process 27593 exited on signal 11
2016/12/26 19:37:48 [alert] 27592#0: worker process 27596 exited on signal 11
2016/12/26 19:37:49 [alert] 27592#0: worker process 27594 exited on signal 11

dmesg報錯:

[51059663.024824] nginx[32061]: segfault at 0 ip 00000000004248db sp 00007fffffba9b70 error 4 in nginx[400000+92000]
[51059668.968624] show_signal_msg: 54 callbacks suppressed
[51059668.968628] nginx[32115]: segfault at 0 ip 00000000004248db sp 00007fffffba9b30 error 4 in nginx[400000+92000]
[51059669.036477] nginx[32184]: segfault at 0 ip 00000000004248db sp 00007fffffba9b30 error 
這種資訊一般都是由核心記憶體訪問越界造成的,不管是使用者態程式還是核心態程式訪問越界都會出core,並在系統日誌裡面輸出一條這樣的資訊。這條資訊的前面分別是訪問越界的程式名,程序id號,訪問越界的地址以及當時程序程序堆疊地址等資訊,比較有用的資訊是最後的error number.在上面的資訊中。 error number是由3個字位組成的,從高到低分別是bit2、bit1、bit0,轉成二進位制就是100,即bit2=1,bit1=0,bit0=0,所以它的取值範圍是0~7,每個字位的含義是:
bit2:值為1時表示 是使用者態程式記憶體訪問越界,值為0時表示 是核心態程式記憶體訪問越界
bit1:值為1時表示 是寫操作導致記憶體訪問越界,值為0時表示 是讀操作導致記憶體訪問越界
bit0:值為1表示沒有足夠的許可權訪問非法地址的內容,值為0時表示訪問的非法地址根本沒有對應的頁面,也就是無效地址。
因此error number 是4,就表示使用者態程式nginx進行讀操作時訪問的地址無效。在查找了大量資料之後,從 https://toontong.github.io/blog/nginx-gdb-coredump-segfault.html 這裡找到了問題的所在原因。由於我們整站都是使用HTTPS,所以需要在nginx的ssl模組新增如下配置:
ssl_session_cache   shared:SSL:1024m;
ssl_session_timeout 10m;
重啟nginx,完美過坑。

本文來自網易實踐者社群,經作者齊紅方授權釋出。