摘要
- 在 TLS 1.3 中,
close_notify是带认证的单向声明:发送方此后不会在该连接上发送更多 TLS 消息。它不关闭对端的发送方向,也不确认请求、响应、流或持久化副作用。 - 底层传输在没有该告警时出现 EOF,会保留截断歧义。只有上层协议拥有独立而明确的消息完整性规则,且应用确实执行了检查,兼容策略才可能把这种 EOF 作为可接受终止。
- 重试与归责需要四道分开保存的边界:应用消息终点、本地与对端 TLS 关闭、传输终止、业务持久结果。一个
closed=true字段没有这些权限。
“关闭成功”回答错了问题
事故日志最后一行是 shutdown=success。运维人员起初把它理解为响应已送达、交易已完成。这个字段其实来自 TLS 封装层,只说明本地关闭流程进入了成功分支。
服务器先构造成功响应,再尝试提交状态。响应记录被写入 TLS,随后发出 close_notify。数据库在最后阶段遇到唯一性冲突,拒绝提交。客户端拿到的是一个真实且有序的密码学终点,却没有拿到提交编号。
TLS 能证明服务器选择发送的记录位于告警之前。它看不到数据库事务,更不知道远端应用是否消费了这些字节。把最后一个网络事件升级为业务权威,才是这起故障的核心。
一个连接有两个结束方向
TLS 1.3 对两个方向分别关闭。发送 close_notify 的一方承诺不再发送 TLS 消息;告警之后到达的数据必须被忽略。但它仍可继续读取,因为对端可能还有最后的数据要发,然后才关闭自己的方向。
除非已经发送错误告警,每一方都应在关闭写侧前发送 close_notify。TLS 1.3 不再要求收到告警后立即回告并丢弃待发送数据,因为旧行为可能截断接收方仍未发完的输出。
TCP 也有半关闭,但证据性质不同。FIN 只界定一个有序字节流的结束。它不是带认证的 TLS 告警,不能指出最后一个完整 TLS 记录,也不理解应用消息。
EOF 留下的不是结论,而是歧义
底层传输在 close_notify 之前关闭时,接收方无法判断发送方原本打算发送的数据是否全部到达。原因可能是进程崩溃、代理超时、旧实现不兼容,也可能是主动截断。缺少告警不等于攻击成立,但意味着更强的密码学边界不存在。
致命告警、RST、超时、意外 EOF、收到关闭告警和本地尝试发送告警,也必须是不同状态。若全部显示为“断开”,调查者将失去判断消息能否使用、操作能否重试所需的顺序和方向。
IANA 把告警值 0 分配给 close_notify。这能证明代码点和规范引用,不能证明某条生产连接确实发出或收到它,更不能证明告警之前的应用消息完整。
TLS 不知道一条消息在哪里结束
受到保护的记录先于 close_notify 到达,只能说明它们与告警之间的顺序。对 TLS 而言,内容是不透明字节;它不知道里面是完整文档、最终响应、提交凭证,还是半条结构化消息。
应用协议必须拥有自己的终点,例如声明长度、终止分块、流 FIN、最终状态码、确认消息、请求编号或持久化记录。哪一种有效,由上层协议决定。完整响应仍可能报告失败;成功操作也可能在响应返回前就已提交。
缓冲区还会增加中间状态。一次写调用被接受,可能只表示字节进入 TLS 或 BIO 缓冲。非阻塞程序也可能先记录“已尝试发送告警”,随后才真正把字节交给传输层。这些事件都不构成数据库提交证据。
OpenSSL 的返回值是一条状态序列
SSL_shutdown() 首次返回 0,通常表示本地 close_notify 已发出,而对端告警仍未收到。这不是错误,也不是双向完成。返回 1 才表示双方告警均已发送和接收。
第一步关闭 TLS 写侧,读侧仍可工作,底层 TCP 也仍然打开。OpenSSL 建议继续读取,以处理最后的应用数据和握手后消息。若待处理应用数据尚未排空就再次调用关闭,操作可能失败。
内部标志同样要按原义保存:sent 记录发送尝试,received 记录对端告警。quiet shutdown 只是把本地状态标成关闭,不发送告警,因此不符合协议。OpenSSL 3.0 起,意外 EOF 有明确错误含义;只有应用协议能无歧义发现截断并真正执行检查时,SSL_OP_IGNORE_UNEXPECTED_EOF 才有成立条件。
GnuTLS 用 GNUTLS_SHUT_WR 和 GNUTLS_SHUT_RDWR 区分只关写侧与等待对端。BoringSSL 的运行状态机也分别跟踪读写关闭。库提供了可区分的事实,扁平监控却可能再次把它们抹掉。
HTTP 展示了上层边界
HTTP/1.1 有自己的完整性规则。Content-Length 要求收到声明数量的字节;chunked 编码要求终止的零长度分块。任一条件不满足,连接关闭都不能把响应变成完整消息。
只靠关闭界定长度的响应风险更高。它的消息终点依赖连接正确结束,所以不完整的 TLS 关闭会使 HTTP 响应也不完整。RFC 9112 建议使用明确长度或编码,正是因为网络故障可能伪装成正常结束。
若声明长度或终止分块已经核验,即使随后缺少对端告警,该消息边界仍是有效证据。这也是忽略某些 EOF 的精确前提:应用必须逐条证明它准备采用的消息有独立终点,而不是只打开一个兼容选项。
多路复用还需要请求范围
HTTP/2 在同一 TLS 连接上承载多条流。close_notify 无法指出服务器已经开始处理哪些请求。GOAWAY 提供最后流编号的边界:更高编号可以重试,边界内的请求仍可能已经执行。
若连接在没有 GOAWAY 时结束,一条在途的非幂等 POST 仍处于不确定状态。HTTP/3 在 QUIC 之上采用同样思路,以自己的 GOAWAY 限定已接受请求范围。连接关闭不会凭空生成请求级确认。
把所有“正常关闭”前的请求都重试,可能造成双重扣款;一律不重试,也可能丢失工作。重试权限来自方法语义、幂等键、结果查询和对账,而不是“优雅关闭”这个形容词。
QUIC 使用另一套终止机制
QUIC 承载 TLS 握手字节,却不用 TLS 记录保护应用数据。TLS 告警被转换为 QUIC 连接错误;QUIC 自己拥有 CONNECTION_CLOSE、流 FIN、reset、closing 和 draining 状态。TLS close_notify 的 warning 语义不能搬到 QUIC。
HTTP/3 仍需要 GOAWAY,因为 QUIC 连接终止也不能单独说明哪些请求被接受。指标必须写明实际载体:TLS 告警、TCP FIN 或 RST、QUIC 流 FIN、CONNECTION_CLOSE、空闲超时、HTTP GOAWAY 或应用确认。
让结束能够被审计
每条连接应记录端点角色、方向、TLS 版本、关联标识,以及最后一条完整应用消息或流。保存消息边界规则、预期与实收字节数、请求编号、幂等键和重试类别。
TLS 侧要区分本地告警入队、实际发出、对端告警收到,保存库返回序列、读写关闭标志、待处理明文或密文和准确错误分类。quiet 模式、EOF 策略、库版本、kTLS 与代理边界也应进入证据。
传输侧分别记录 FIN、RST、EOF、超时和半关闭;多路协议保存 GOAWAY 范围及逐流终点;业务侧保存确认、提交编号、持久时间戳和签发这些事实的权威系统。
负向测试要覆盖:告警前切断 TCP、删掉 HTTP 终止分块、完整帧后但提交前关闭、首次返回 0、对端数据未读、quiet shutdown、切换 EOF 兼容策略,以及 HTTP/2 或 HTTP/3 中非幂等请求在途时断开。
来源
- https://www.rfc-editor.org/rfc/rfc9846.html
- https://www.rfc-editor.org/rfc/rfc9293.html
- https://www.rfc-editor.org/rfc/rfc9112.html
- https://www.rfc-editor.org/rfc/rfc9113.html
- https://www.rfc-editor.org/rfc/rfc9000.html
- https://www.rfc-editor.org/rfc/rfc9001.html
- https://www.rfc-editor.org/rfc/rfc9114.html
- https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml
- https://docs.openssl.org/3.5/man3/SSL_shutdown/
- https://docs.openssl.org/master/man3/SSL_get_error/
- https://docs.openssl.org/master/man3/SSL_CTX_set_options/
- https://www.gnutls.org/manual/html_node/Core-TLS-API.html
- https://boringssl.googlesource.com/boringssl/+/refs/heads/main/ssl/ssl_lib.cc
- https://heng.lu/running-code-primary-the-patch-needed-to-preserve-the-internet-original-design/
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
