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报文格式就知道了!

posted @ 2020-07-01 23:50  小伍子  阅读(22456)  评论(2编辑  收藏  举报