Nginx學(xué)習(xí):SSL模塊(二)錯(cuò)誤狀態(tài)碼、變量及寶塔配置分析
繼續(xù)我們的 SSL 模塊的學(xué)習(xí)。上回其實(shí)我們已經(jīng)搭建起了一個(gè) HTTPS 服務(wù)器了,只用了三個(gè)配置,其中一個(gè)是 listen 的參數(shù),另外兩個(gè)是指定密鑰文件的地址,一個(gè)是 crt 文件,一個(gè)是 key 文件。今天我們將學(xué)習(xí)到的是 SSL 中的錯(cuò)誤狀態(tài)碼、變量相關(guān)的內(nèi)容,以及最后會(huì)看一下在寶塔中配置 SSL 之后,它生成的配置指令是什么樣的。
今天的內(nèi)容不多,但最后的寶塔配置分析還是值得一看的。畢竟要解決的就是大家知其然,也要知其所以然的問(wèn)題。而先前的我,正是不知其所以然。因此,很多時(shí)候,用工具可以配,但是配了之后不敢動(dòng),生怕出現(xiàn)什么問(wèn)題。因?yàn)榕涑鰜?lái)的內(nèi)容完全不懂是在干嘛呀。咱們今天,主力先解決這個(gè)問(wèn)題。
錯(cuò)誤狀態(tài)碼
首先就是錯(cuò)誤狀態(tài)碼,在 Nginx 的 SSL 模塊中,支持幾個(gè)非標(biāo)準(zhǔn)錯(cuò)誤代碼,可用于使用 error_page 指令進(jìn)行重定向:
495 客戶端證書驗(yàn)證過(guò)程中發(fā)生錯(cuò)誤。
496 客戶未出示所需的證書。
497 已向 HTTPS 端口發(fā)送常規(guī)請(qǐng)求。
重定向發(fā)生在請(qǐng)求被完全解析并且變量(例如 $request_uri、$uri、$args等)可用之后。這三個(gè)狀態(tài)碼大家了解一下,如果遇到了返回這三個(gè)狀態(tài)碼信息的時(shí)候,千萬(wàn)別慌,趕緊看看 SSL 的配置是否有問(wèn)題。
SSL 相關(guān)變量
SSL 模塊中提供的變量非常多,可以說(shuō)是僅次于 HTTP 核心模塊提供的變量數(shù)量了。這些變量?jī)?nèi)容也是大家了解一下即可。
$ssl_alpn_protocol返回 ALPN 在 SSL 握手期間選擇的協(xié)議,否則返回空字符串 (1.21.4)。
$ssl_cipher返回用于已建立 SSL 連接的加密算法的名稱。
$ssl_ciphers返回客戶端 (1.11.7) 支持的加密算法列表。已知密碼按名稱列出,未知密碼以十六進(jìn)制顯示。只有在使用 OpenSSL 1.0.2 或更高版本時(shí)才完全支持該變量。對(duì)于舊版本,該變量?jī)H可用于新會(huì)話并且僅列出已知密碼。
$ssl_client_escaped_cert為已建立的 SSL 連接 (1.13.5) 返回 PEM 格式(urlencoded)的客戶端證書。
$ssl_client_cert為已建立的 SSL 連接返回 PEM 格式的客戶端證書,除第一行之外的每一行都以制表符開(kāi)頭;這旨在用于 proxy_set_header 指令。該變量已棄用,應(yīng)改為使用 $ssl_client_escaped_cert變量。
$ssl_client_fingerprint返回已建立 SSL 連接 (1.7.1) 的客戶端證書的 SHA1 指紋。
$ssl_client_i_dn根據(jù) RFC 2253 (1.11.6) 返回已建立 SSL 連接的客戶端證書的“頒發(fā)者 DN”字符串。
$ssl_client_i_dn_legacy返回已建立 SSL 連接的客戶端證書的“頒發(fā)者 DN”字符串,在 1.11.6 版本之前,變量名稱是 $ssl_client_i_dn。
$ssl_client_raw_cert為已建立的 SSL 連接返回 PEM 格式的客戶端證書。
$ssl_client_s_dn根據(jù) RFC 2253 (1.11.6) 返回已建立 SSL 連接的客戶端證書的“主題 DN”字符串。
$ssl_client_s_dn_legacy返回已建立 SSL 連接的客戶端證書的“主題 DN”字符串,在 1.11.6 版本之前,變量名稱是 $ssl_client_s_dn。
$ssl_client_serial返回已建立 SSL 連接的客戶端證書的序列號(hào)。
$ssl_client_v_end返回客戶端證書的結(jié)束日期(1.11.7)。
$ssl_client_v_remain返回客戶端證書到期前的天數(shù)(1.11.7)。
$ssl_client_v_start返回客戶端證書的開(kāi)始日期(1.11.7)。
$ssl_client_verify如果證書不存在,則返回客戶端證書驗(yàn)證的結(jié)果:“SUCCESS”、“FAILED:reason”和“NONE”,在 1.11.7 版本之前,“FAILED”結(jié)果不包含原因字符串。
$ssl_curve返回用于 SSL 握手密鑰交換過(guò)程 (1.21.5) 的協(xié)商曲線。已知曲線按名稱列出,未知曲線以十六進(jìn)制顯示。僅當(dāng)使用 OpenSSL 3.0 或更高版本時(shí)才支持該變量。對(duì)于舊版本,變量值將是一個(gè)空字符串。
$ssl_curves回客戶端 (1.11.7) 支持的曲線列表。已知曲線按名稱列出,未知曲線以十六進(jìn)制顯示。僅當(dāng)使用 OpenSSL 1.0.2 或更高版本時(shí)才支持該變量。對(duì)于舊版本,變量值將是一個(gè)空字符串。該變量?jī)H適用于新會(huì)話。
$ssl_early_data如果使用 TLS 1.3 早期數(shù)據(jù)并且握手未完成,則返回“1”,否則返回“”(1.15.3)。
$ssl_protocol返回已建立的 SSL 連接的協(xié)議。
$ssl_server_name返回通過(guò) SNI (1.7.0) 請(qǐng)求的服務(wù)器名稱。
$ssl_session_id返回已建立 SSL 連接的會(huì)話標(biāo)識(shí)符。
$ssl_session_reused如果 SSL 會(huì)話被重用,則返回“r”,或否則返回“.”(1.5.11)。
我們可以通過(guò)記錄記錄訪問(wèn)日志來(lái)查看這些變量的設(shè)置情況,比如像下面這樣配置。log_format ssl 'ssl_alpn_protocol=$ssl_alpn_protocol ssl_cipher=$ssl_cipher ssl_ciphers=$ssl_ciphers'
'ssl_client_escaped_cert=$ssl_client_escaped_cert ssl_client_cert=$ssl_client_cert ssl_client_fingerprint=$ssl_client_fingerprint'
'ssl_client_i_dn=$ssl_client_i_dn ssl_client_i_dn_legacy=$ssl_client_i_dn_legacy ssl_client_raw_cert=$ssl_client_raw_cert'
'ssl_client_s_dn=$ssl_client_s_dn ssl_client_s_dn_legacy=$ssl_client_s_dn_legacy ssl_client_serial=$ssl_client_serial'
'ssl_client_v_end=$ssl_client_v_end ssl_client_v_remain=$ssl_client_v_remain ssl_client_v_start=$ssl_client_v_start'
'ssl_client_verify=$ssl_client_verify ssl_curve=$ssl_curve ssl_curves=$ssl_curves'
'ssl_early_data=$ssl_early_data ssl_protocol=$ssl_protocol ssl_server_name=$ssl_server_name'
'ssl_session_id=$ssl_session_id ssl_session_reused=$ssl_session_reused';
server{
………………
access_log logs/37.log ssl;
}
配置成功后,訪問(wèn) https 頁(yè)面,日志中就會(huì)記錄下面這些內(nèi)容。ssl_alpn_protocol=- ssl_cipher=ECDHE-RSA-AES128-GCM-SHA256 ssl_ciphers=TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:DES-CBC3-SHAssl_client_escaped_cert=- ssl_client_cert=- ssl_client_fingerprint=-ssl_client_i_dn=- ssl_client_i_dn_legacy=- ssl_client_raw_cert=-ssl_client_s_dn=- ssl_client_s_dn_legacy=- ssl_client_serial=-ssl_client_v_end=- ssl_client_v_remain=- ssl_client_v_start=-ssl_client_verify=NONE ssl_curve=- ssl_curves=X25519:prime256v1:secp384r1ssl_early_data=- ssl_protocol=TLSv1.2 ssl_server_name=-ssl_session_id=- ssl_session_reused=.
好吧,不得不說(shuō),這一堆變量也是看得我一臉懵逼。除了 ssl_protocol 是協(xié)議版本,ssl_cipher 是加密算法之外 ,其它的很多都不知道是干嘛的。但是呢,就像之前在學(xué)習(xí) PHP 加解密相關(guān)的文章時(shí)也說(shuō)過(guò)。本身加解密就是一塊非常大的而且非常深的內(nèi)容,如果只是為了日常應(yīng)用,那么了解到這個(gè)程度也就夠了。大家如果一點(diǎn)都不了解的話,可以去我的 PHP 文章學(xué)習(xí)一下哦。
PHP加解密http://www.zyblog.com.cn/t/加解密
寶塔 SSL 配置
最后,我們就來(lái)看看寶塔面板配置出來(lái)的 SSL 配置是啥樣的。在寶塔中,大家可以使用免費(fèi)的 Let's Encrypt 證書。這個(gè)證書是免費(fèi)的,但是要經(jīng)常續(xù)簽。一般云服務(wù)上的免費(fèi)證書都是一年,收費(fèi)則是可選年份的,而這個(gè)基本是 40 來(lái)天。它的續(xù)簽寶塔也會(huì)自動(dòng)在定時(shí)任務(wù)中加上。因此,這個(gè)就相當(dāng)于是徹底免費(fèi)的一套證書。不過(guò),和很多免費(fèi)證書一樣,它做不了泛域名,也就是 *.zyblog.com.cn 這樣對(duì)整個(gè)域名的證書。只能每個(gè)子域名選擇性地簽發(fā)。
在配置好 Let's Encrypt 并自動(dòng)簽發(fā)成功后,SSL 頁(yè)面就會(huì)顯示成這樣。
如果你是自己通過(guò)阿里云、騰訊云或者其它任何機(jī)構(gòu)購(gòu)買的證書,那么也需要將拿到的證書中的內(nèi)容復(fù)制過(guò)來(lái),左邊是 .key 文件的內(nèi)容,右邊是 .pem 文件的內(nèi)容。直接復(fù)制粘貼進(jìn)來(lái)就可以用了。自己購(gòu)買的證書要保管好哦。
接下來(lái)看看配置文件中生成的 SSL 部分內(nèi)容。#SSL-START SSL相關(guān)配置,請(qǐng)勿刪除或修改下一行帶注釋的404規(guī)則
#error_page 404/404.html;
#HTTP_TO_HTTPS_START
if ($server_port !~ 443){
rewrite ^(/.*)$ https://$host$1 permanent;
}
#HTTP_TO_HTTPS_END
ssl_certificate /www/server/panel/vhost/cert/roadmap.zyblog.com.cn/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/roadmap.zyblog.com.cn/privkey.pem;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
add_header Strict-Transport-Security "max-age=31536000";
error_page 497 https://$host$request_uri;
#SSL-END
不能刪除或修改帶注釋的 404 規(guī)則這個(gè),我也不明白是啥意思,有懂得小伙伴可以留言哦。
HTTP_TO_HTTPS_START 注釋部分的判斷,其實(shí)就是上圖中,我開(kāi)啟了 強(qiáng)制HTTPS 才會(huì)生成的內(nèi)容。也就是如果我們?cè)L問(wèn)當(dāng)前 server 時(shí),使用的不是 443 端口,就強(qiáng)制跳到 443 端口。這樣就能保證訪問(wèn)的一直是 HTTPS 頁(yè)面。這個(gè)配置也是比較常用的。
ssl_certificate 和 ssl_certificate_key 不多解釋了。
ssl_protocols 在上篇文章中不知道大家注意過(guò)沒(méi),它的默認(rèn)值是 TLSv1 TLSv1.1 TLSv1.2 ,這里的配置去掉了 TLSv1 ,加上了 TLSv1.3 。很明顯,這是拋棄了老版本,加上了新版本嘛。
ssl_ciphers 指定可用的加密算法,這個(gè)配置和上面的 $ssl_cipher以及 $ssl_ciphers也有關(guān)系。主要就是在建立 TLS 連接時(shí),具體要使用的加密算法范圍。主要其實(shí)是要和客戶端瀏覽器做兼容,不過(guò)這里添加的算法并不多。因此需要開(kāi)啟下面那個(gè)配置項(xiàng)。更多的我也不清楚了,有了解的小伙伴一定要在評(píng)論區(qū)不吝賜教哦。
開(kāi)啟 ssl_prefer_server_ciphers ,讓服務(wù)器加密算法為主要算法來(lái)進(jìn)行加密。
設(shè)置 ssl_session_cache ,指定所有工作進(jìn)程之間共享的緩存空間名稱為 SSL ,有 10m 大小。使用 SSL Session 可以減少 TLS 的反復(fù)驗(yàn)證,1M 的緩存可以緩存 4000 個(gè)連接,因此,10M 可以達(dá)到 40000 個(gè)連接。對(duì)于一般網(wǎng)站來(lái)說(shuō),完全夠用了。是非常有用的性能提升手段,推薦配置。
設(shè)置 ssl_session_timeout 指定客戶端可以重用會(huì)話參數(shù)的時(shí)間,也就是上面那個(gè)緩存的過(guò)期時(shí)間,這里設(shè)置的是 10 分鐘。
添加 Strict-Transport-Security 響應(yīng)頭,用于告訴瀏覽器,這個(gè)網(wǎng)站應(yīng)該只使用 HTTPS 而不是使用 HTTP 進(jìn)行訪問(wèn)。設(shè)置的內(nèi)容是一個(gè)以秒為單位的時(shí)間戳,表示的是過(guò)期的時(shí)候,31536000 表示的時(shí)間是一年(31536000/60/60/24=365)。過(guò)了這個(gè)時(shí)間之后,瀏覽器就會(huì)認(rèn)為這個(gè)地址又可以使用 HTTP 訪問(wèn)了。前提是,如果這一年它沒(méi)再打開(kāi)過(guò)這個(gè)網(wǎng)站,否則咱們的響應(yīng)每次都會(huì)返回這個(gè)時(shí)間嘛,日期也會(huì)一直向后拖。對(duì)于經(jīng)常訪問(wèn)的站點(diǎn)來(lái)說(shuō),這個(gè)過(guò)期時(shí)間就相當(dāng)于是永久了。
最后,有個(gè) error_page 配置,當(dāng)錯(cuò)誤狀態(tài)碼為 497 ,使用 HTTP 訪問(wèn) HTTPS 頁(yè)面時(shí),會(huì)報(bào)出這個(gè)狀態(tài)碼錯(cuò)誤。然后 errpr_page 直接指向 https 協(xié)議的當(dāng)前訪問(wèn)頁(yè)面。其實(shí)這也是一種強(qiáng)制 HTTPS 訪問(wèn)的效果。
總結(jié)
好了,今天的內(nèi)容不多吧?而且我們?cè)谡麄€(gè) SSL 模塊中也沒(méi)有做過(guò)多的測(cè)試,就是最開(kāi)始配置的那個(gè)最簡(jiǎn)單的 SSL 服務(wù)。說(shuō)實(shí)話,這一塊的很多配置我真的沒(méi)用過(guò),也完全不知道是啥意思。甚至在今天的學(xué)習(xí)之前,我也并不清楚 ssl_ciphers、ssl_session_cache 到底是干嘛用的。真的只知道 ssl 、ssl_certificate、ssl_certificate_key 這三個(gè)配置。
好吧,話說(shuō)回來(lái),大部分情況下,其實(shí)有這些就已經(jīng)足夠了。還是那句話,當(dāng)你在需要的時(shí)候,能夠隱約想起之前好像在哪兒看過(guò),這玩意 Nginx 有現(xiàn)成的配置就行了。然后再去查文檔、查資料進(jìn)行深入的了解,這才是我們軟件開(kāi)發(fā)(踩坑)的正確姿勢(shì)嘛!
參考文檔:http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_conf_command
聯(lián)系客服