sgcWebSockets 与 sgcOpenAPI 中的 zlib 1.3.1 | eSeGeCe 博客

sgcWebSockets 与 sgcOpenAPI 中的 zlib 1.3.1

· 组件

zlib 是 sgcWebSockets 内部为数不多的第三方 C 代码之一。它支撑着 WebSocket 的 permessage-deflate 扩展,因此服务器发送或接收的每一个压缩帧都会经过它,同时它也负责 HTTP 内容编码。sgcOpenAPI 共用同一份源码,所以它使用的也是同一份副本。从 2026.8.0 开始,这份副本从 zlib 1.2.12 升级到 zlib 1.3.1。

这一变化在 API 层面是不可见的。你的代码无需做任何改动,压缩行为也保持不变。真正值得说明的是,为什么一个小型 C 库的版本升级不只是替换一个文件,以及我们做了哪些工作来确保它在我们支持的每个编译器上都是安全的。

1.3.1 修复了什么,以及为什么你并未受到影响

1.2.12 与 1.3.1 之间最受关注的修复是 CVE-2022-37434,这是 inflate() 中的一处堆越界读取。只有当调用方向 zlib 传入一个 extra 字段指向某个缓冲区的 gz_header 时,才可能触发。zlib 随后会把 gzip 的 extra 字段复制进去,而在 1.2.12 中这次复制缺少边界检查。

sgcWebSockets 从未满足该条件。它调用 inflateGetHeader 时始终传入一个零初始化的 gz_header,并且从不为 head.extra 赋值,因此受影响的分支根本无法进入。在决定如何处理之前,我们已在源码中核实了这一点,并且明确表态:使用早期版本构建的应用程序不会通过这条路径受到攻击。

但我们仍然做了更新。自动化扫描工具和供应商问卷读取的是版本字符串,而不是调用图,运行依赖扫描的客户不应该为了消除一条告警而去重建我们的推理过程。升级可以一劳永逸地结束这个话题,而不是让它被反复提起。

为什么更新 zlib 不只是替换文件

zlib 是被编译进你的可执行文件的,而不是以 DLL 形式部署,这就是为什么 sgcWebSockets 应用程序旁边没有 zlib1.dll。这种链接是通过预编译的目标文件完成的,而 Delphi 对它们的格式非常挑剔。因此,更新 zlib 意味着要重新构建这些目标文件,而且不止一套,是三套。

使用者格式构建工具
Delphi 7 到 XEOMFbcc32ZEXPORT=__fastcall
XE2 及更高版本,Win32OMFbcc32ZEXPORT=__cdecl
XE2 及更高版本,Win64COFFMSVC cl

两套 32 位目标文件的区别在于调用约定,因为较旧的编译器使用 Delphi 的寄存器约定来链接 zlib,而 XE2 及更高版本使用 cdecl。64 位那一套则是另一种目标文件格式。值得一提的是,bcc64 无法生成它,因为它输出的是 ELF 目标文件,而 Delphi 的 Win64 链接器需要 COFF,所以那一套是用微软的编译器构建的。

这一切对你来说都是不可见的。它只是说明了为什么 zlib 的版本升级是一项构建工作,而不是一次下载。

在每一个编译器上验证,而不只是最新的那个

重新构建的目标文件可能编译通过却仍然是错的,所以仅做链接测试并不足够。我们用每一个受支持的编译器构建并运行了一个程序,它压缩一个缓冲区、再解压、逐字节比对,并断言链接进来的目标文件报告的版本符合预期。

uses
  sgcIdCTypes, sgcIdGlobal, sgcIdZLibHeaders;

var
  vPackedLen: TIdC_ULONG;
begin
  vPackedLen := SizeOf(vPacked);
  if compress(PIdAnsiChar(@vPacked[0]), vPackedLen,
              PIdAnsiChar(@vSrc[0]), SizeOf(vSrc)) <> 0 then
    raise Exception.Create('compress failed');

  WriteLn('zlib ', String(AnsiString(zlibVersion)));   // zlib 1.3.1
end;

该程序在 Delphi 7、Delphi 2007、Delphi 2009 以及 RAD Studio XE6 到 13 上运行过,涵盖 Win32 以及存在该平台的 Win64。全部 25 种组合均通过,并报告 1.3.1。

顺带修复的一个潜在 64 位缺陷

这个测试矩阵还发现了一个与新版本毫无关系的问题。在 Delphi 10 Seattle 上,64 位构建选中的却是 32 位目标文件,它们无法链接进 64 位可执行文件,会产生 Bad object file format 错误。原因是一段用于绕开 Seattle 特有问题的旧条件编译,它把这一种组合导向了错误的目标文件集。现在 Seattle 的 64 位构建与其他所有 64 位目标使用同一套目标文件,并且可以正常编译。

sgcOpenAPI 同步获得此更新

sgcOpenAPI 与 sgcWebSockets 共用源码,其中也包括 zlib,因此它会在同一个版本中升级到 1.3.1,你无需另行操作。

你需要做什么

安装 2026.8.0 并重新编译你的项目。没有属性需要设置,没有单元需要添加或移除,也没有部署上的变化,因为 zlib 原本就在你的可执行文件里,现在依然如此。如果你为自己的产品维护软件物料清单,请把 zlib 条目更新为 1.3.1,同时可以删除此前记录的任何 CVE-2022-37434 说明。