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

### 解决Nginx TLS握手失败 当面对Nginx处理TLS握手失败的情况时,可以从多个角度排查问题。通常情况下,这类问题可能源于证书配置不当、协议版本或密码套件不兼容等问题。 #### 1. 检查并修正证书配置 确保所使用的SSL/TLS证书处于有效期内,并且是由受信认证机构签发的[^1]。如果证书存在问题(例如过期、自签名或不受信任),则可能导致握手失败。建议定期更新证书,并确认其正确安装于Nginx环境中。 #### 2. 验证协议与密码套件的一致性 客户端和服务器之间必须就共同支持的SSL/TLS版本达成一致;同样地,双方也需同意使用相同的密码套件来进行加密操作。可以通过调整Nginx配置文件中的`ssl_protocols`和`ssl_ciphers`指令来指定允许使用的最低协议版本以及可用的密码组合: ```nginx server { listen 443 ssl; server_name example.com; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; # 设置最小TLS版本为1.2及以上 ssl_protocols TLSv1.2 TLSv1.3; # 定义优先级较高的现代密码套件 ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256'; } ``` #### 3. 排除服务器端配置错误 除了上述两点外,还需注意其他潜在因素,比如证书链是否完整加载、私钥权限设置是否恰当等。任何细微之处都可能是造成握手失败的原因之一。此外,还应留意操作系统层面是否存在资源耗尽现象,如文件描述符数量不足等情况也会干扰正常的服务运行。 #### 4. 使用工具辅助诊断 对于难以定位的问题,借助专门设计的安全检测工具往往能事半功倍。OpenSSL自带了一个名为`s_client`的强大命令行实用程序,可用于模拟HTTPS请求并向目标站点发起连接尝试,从而获取详细的握手过程记录以便进一步分析: ```bash openssl s_client -connect www.example.com:443 -servername www.example.com -tls1_2 ``` 此命令将显示整个握手过程中涉及的各项参数及其状态变化情况,有助于快速识别具体哪个环节出现了异常。 --- ### 处理十六进制编码的数据包 针对捕获到的十六进制形式表示的数据流,在实际工作中经常需要用到Wireshark这样的网络协议分析器来进行可视化解读。不过在此之前,也可以利用Python脚本初步转换这些原始字节串成更易读取的形式,如下所示: ```python def hex_to_ascii(hex_string): bytes_object = bytes.fromhex(hex_string.replace(' ', '')) ascii_string = bytes_object.decode("ASCII", errors='replace') return ascii_string if __name__ == "__main__": hex_data = "17030300ff..." # 替换成真实的Hex字符串 print(f"Parsed ASCII content:\n{hex_to_ascii(hex_data)}") ``` 这段简单的函数能够把由空格分隔开来的连续两位十六进制数值组成的字符串转化为对应的ASCII字符序列,方便后续人工审查其中携带的信息片段[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值