OpenSSL报unexpected eof while reading错误处理咨询
自主开发基于2022年7月发布版OpenSSL库的Web服务器,初始化阶段通过SSL_CTX_set_min_proto_version(sslctx, TLS1_3_VERSION);将TLS 1.3设置为最低支持协议版本。
当前简化后的客户端接入处理流程为:
- 调用
SSL_new()创建SSL会话对象 - 调用
SSL_set_fd()为SSL对象绑定套接字文件描述符 - 调用
SSL_accept()完成TLS握手流程 - 基于
SSL_accept()返回值执行错误校验 - 调用
SSL_read()读取客户端发送的请求数据 - 调用
SSL_write()向客户端返回响应数据 - 调用
SSL_shutdown()执行TLS连接关闭流程 - 调用
SSL_free()释放SSL对象资源 - 调用
close()关闭底层套接字
常规访问场景下服务运行正常,在Kubuntu 22.04 64位系统上使用Firefox 102.0 64位浏览器可正常访问服务。但长按F5频繁刷新页面/资源时,错误校验逻辑会捕获报错:error:0A000126:SSL routines::unexpected eof while reading。
查阅OpenSSL官方文档可知,部分TLS实现不会按协议规范发送要求的close_notify关闭告警,针对该场景可在初始化阶段调用SSL_CTX_set_options()时添加SSL_OP_IGNORE_UNEXPECTED_EOF标志抑制该错误。已知Firefox在正常场景下会发送close_notify告警,仅在连续高频请求的特殊场景下未正常发送,需确认直接抑制该错误是否存在安全风险,或是现有逻辑存在遗漏需要额外适配高频刷新场景。
直接开启SSL_OP_IGNORE_UNEXPECTED_EOF不存在额外安全风险,该报错是浏览器主动中断连接的正常行为,现有处理流程不存在逻辑缺陷,不需要针对高频刷新场景开发特殊适配逻辑。
具体说明
- 高频刷新下的浏览器行为符合预期
长按F5触发连续刷新时,浏览器会直接中断当前已建立或正在传输的TCP/TLS连接,立刻发起新的页面请求,不会等待现有连接走完TLS规范要求的close_notify双向关闭流程。这不是Firefox的独有问题,所有主流浏览器在主动取消请求、用户强制刷新、页面跳转中断现有请求的场景下,都会直接关闭底层TCP连接(发送RST或FIN包),不会发送TLS层的close_notify告警。 SSL_OP_IGNORE_UNEXPECTED_EOF无安全隐患
该选项的作用范围非常明确,仅会屏蔽连接数据传输过程无篡改、无异常截断的前提下,对端未发送close_notify就直接断开连接的报错,不会影响TLS握手阶段的安全校验,也不会放过传输过程中被篡改、恶意截断的流量,不存在触发降级攻击、截断攻击的风险。OpenSSL官方本身就将该选项作为兼容现实环境中不严格遵守TLS关闭规范实现的标准方案,主流浏览器的主动断连行为本身就在该选项的适配范围内。- 现有资源释放逻辑无需调整
你当前实现的连接关闭、资源回收流程是正确的,捕获到该unexpected eof错误后,按现有流程依次执行SSL_shutdown()、SSL_free()、关闭底层套接字即可。唯一需要调整的是日志分级:不要把该错误归类为服务端故障打error级别日志,归为客户端主动断连的常规事件即可,避免产生大量无意义日志占用存储。
补充说明:TLS规范要求发送
close_notify的初衷是防范传输中段截断攻击,即攻击者在数据传输未完成时恶意切断连接,让接收方将半截数据误判为完整内容。但Web场景下HTTP协议本身自带完整性校验机制:无论是Content-Length头还是分块传输编码的终止块,都能明确判断请求/响应报文是否完整接收。只要应用层完成了HTTP报文完整性校验,即使对端未发送close_notify,也不存在实际的截断攻击风险。
内容的提问来源于stack exchange,提问作者Schrödinger's cat

