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

文章讲述了在尝试为个人网站启用HTTPS时遇到的问题,浏览器显示ERR_SSL_PROTOCOL_ERROR。作者发现Nginxaccess日志中的$request字段显示为十六进制字符串。经过分析,确定这是由于Nginx未正确配置SSL,将HTTPS的客户端hello报文错误地解析为HTTP请求。抓包工具验证了这个理论。同时,文章也探讨了HTTP与HTTPS的连接过程以及Nginx日志中十六进制字符串的来源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

心血来潮想给自己的小网站加上https协议,照着网上一顿操作,结果浏览器提示“ERR_SSL_PROTOCOL_ERROR”无法打开。查看nginx的error日志没有报错,查看access日志如下,其中$request字段打印的全是十六进制(以\x16\x03\x01\x02\x00\x01开头)。

先说解决办法-启用SSL支持

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

1

2

3

4

5

6

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值