nginx的access日志打印十六進制\x16\x03\x01\x02\x00\x01


背景

心血來潮想給自己的小網站加上https協議,照着網上一頓操作,結果瀏覽器提示“ERR_SSL_PROTOCOL_ERROR”無法打開。查看nginx的error日志沒有報錯,查看access日志如下,其中$request字段打印的全是十六進制(以\x16\x03\x01\x02\x00\x01開頭)。

 

先說解決辦法-啟用SSL支持

不同版本(nginx -v查看)的Nginx啟用ssl的配置不一樣!!

#版本1.15.0及以下
listen 443;
ssl on;

#版本1.15.0以上
listen 443 ssl;

 

--------- 分割線 ---------

再看看這一串十六進制怎么回事

有幾個疑問需要解決一下:

1.為什么瀏覽器中訪問一次,access日志會有四條記錄?

本機fiddler抓包發現,瀏覽器中訪問一次,chrome向服務器發出了四次https連接請求。

2.十六進制是亂碼嗎?

.嘗試解碼“\x16\x03...”這一段,失敗不行!其實熟悉ASCII碼就知道這串是轉換不成字符串的,可見字符是從32(空格)開始的

.懷疑是中文,照着網上的方法將nginx的logformat增加一個escape屬性“log_format main escape=json”,結果打印的十六進制部分變成了“\u0016\u0003\u0001\u0002”,失敗!

所以這些十六進制並不是亂碼!怎么肥事?

 

首先查看nginx的logformat可以知道顯示成十六進制的這部分是$request,$request由三個部分組成:http請求方法 http的url http的版本,如“GET / HTTP/1.1.0”。HTTP報文中請求方法與URL直接用空格(\x20)分隔,協議版本和其他內容用換行(\x0A)分隔。

其次對比一下http、https訪問連接服務器過程:

http:  TCP三次握手——發送請求數據——后台處理——返回結果

https: TCP三次握手——客戶端發起https認證請求(第一步由client發送hello報文並帶上相關信息)...

 

Nginx沒有正確開啟支持SSL的情況下,access日志會出現$request字段是十六進制字符串,會不會是Nginx把https認證過程中的第一個hello報文當作http報文進行解析了?

抓包驗證截圖如下,其中報文的原始數據中(最后一個紅框)顯示的十六進制與access日志中打印的十六進制幾乎完全一樣!有興趣的同學可以自行對比驗證一下!

 

結論

在Nginx沒有開啟SSL支持的情況下,Nginx將https連接建立過程中的客戶端hello報文當作http報文處理,暴力的截取了報文中指定位置的十六進制字符串當作了$request的http請求方法、URL和版本號,所以access日志中會出現十六進制字符串。

 

那為什么access日志中4個請求的$request開頭部分是一致的,后面部分又不一致了呢?分析hello報文格式就知道了!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM