2026 年 8 月 13 日,PostgreSQL 一次性修复了 28 个 CVE,创下项目历史纪录。这个数字容易引发错误的判断:是不是 PostgreSQL 变得更不安全了?更值得关注的问题其实是,安全修复从“发布”到“真正运行在生产服务器上”,中间花了多长时间。
这段时间可以称为 补丁延迟(patch latency)。对于运行关键业务的 PostgreSQL 集群,补丁延迟往往比单次发布包含多少个 CVE 更能说明实际风险。
CVE 数量上升,未必意味着代码更糟
PostgreSQL 在 2025 年全年修复了 7 个 CVE,而 2026 年截至目前已经修复了 44 个,其中 28 个集中在 8 月的一次发布中。表面看,这是风险数量突然增加;更准确的解释是,PostgreSQL 正在接受更多安全审查,自动化模糊测试和 AI 辅助研究也提升了发现问题的效率。
这些漏洞中包括缓冲区溢出、整数溢出和类型混淆等经典内存安全问题。这类缺陷可能已经存在多年,直到新的工具和研究方法把它们找出来。漏洞被发现并修复,本身是安全能力增强的表现。
真正需要运营团队关注的是另一条时间线:
安全修复发布 -> CVE 公开 -> PoC 或利用代码出现 -> 攻击者开始扫描 -> 你的生产环境完成修复
CVE 公告通常会说明受影响版本和漏洞类型,有时还会提供足以构造攻击的细节。8 月发布中的一个 to_char() 远程代码执行漏洞已经出现公开概念验证,相关机构也建议立即修复。防守方用 AI 和自动化工具发现漏洞,攻击方同样可以用它们加速漏洞利用。
2025 年初披露的 CVE-2025-1094 就说明了这一点:一个隐藏在 PostgreSQL 字符串转义函数中的 SQL 注入问题,后来出现在真实攻击链中。漏洞在稳定代码中存在多年,但只有在公开披露并被攻击者利用后,才转化为现实风险。
从业务角度看,公开但未修复的 CVE 就像一扇已知的门,旁边还贴着开锁说明。
PostgreSQL 小版本升级通常并不昂贵
PostgreSQL 的 minor release 采用累积修复,并保持二进制兼容。例如:
18.4升级到18.617.10升级到17.1114.23升级到14.24
这类升级通常不需要导出导入数据,也不需要执行 pg_upgrade。基本过程是停止服务、替换二进制文件,再启动服务。在单节点环境中,真正的服务重启可能只需要几秒。
但“替换二进制文件”从来不是整个升级工作的主要成本。测试、变更审批、维护窗口、连接处理、监控确认和回滚准备,才是补丁延迟经常被拉长的原因。
因此,团队需要提前定义 PostgreSQL 补丁 SLA,而不是等 CVE 发布后在聊天群里临时争论:
| 风险级别 | 建议完成时间 |
|---|---|
| 远程代码执行,或已经存在公开利用代码 | 几天内 |
| 高危漏洞,但暂时没有已知利用 | 一到两周内 |
| 其他漏洞 | 下一个计划维护窗口 |
具体时间可以根据业务暴露面、合规要求、集群规模和变更能力调整。关键在于规则要提前确定。这样遇到高危发布时,团队可以直接执行既定流程,而不是重新讨论“这次到底要不要马上打”。
用备用节点把补丁变成例行操作
高可用 PostgreSQL 集群最实用的策略是 先升级备用节点,再切换,再升级旧主节点。这也是 Patroni 等集群环境中常见的滚动升级思路:
- 在 staging 环境验证补丁和应用连接。
- 升级一个备用节点。
- 观察复制延迟、错误日志、连接池和关键查询。
- 将流量切换到已升级的备用节点。
- 升级原主节点,使其重新成为备用节点。
- 确认集群状态恢复正常。
下面是一个适合改造成内部变更脚本的单节点或备用节点检查示例。它假设 PostgreSQL 服务由 systemd 管理,且新二进制已经通过操作系统包管理器安装完成:
#!/usr/bin/env bash
set -euo pipefail
SERVICE="postgresql"
EXPECTED_MAJOR="17"
printf 'Current client version: '
psql --version
if ! pg_isready -q; then
echo "PostgreSQL is not ready before patching" >&2
exit 1
fi
if [[ "$(psql -Atqc 'show server_version;' | cut -d. -f1)" != "$EXPECTED_MAJOR" ]]; then
echo "Unexpected PostgreSQL major version" >&2
exit 1
fi
sudo systemctl stop "$SERVICE"
sudo systemctl start "$SERVICE"
if ! pg_isready -q; then
echo "PostgreSQL did not become ready after patching" >&2
sudo systemctl status "$SERVICE" --no-pager || true
exit 1
fi
psql -Atqc 'select version();'
psql -Atqc 'select now(), pg_is_in_recovery();'
在生产环境中,切勿直接照搬服务名或停止方式。不同发行版、容器部署和 Patroni 集群的管理方式可能不同。生产脚本还应加入连接排空、复制延迟阈值、备份检查、监控静默和明确的回滚步骤。
升级前务必阅读发布说明中的 Updating 部分。大多数 minor release 只需要替换二进制并重启,但某些版本可能要求额外的数据维护。例如本次发布需要关注:
- 如果使用 GIN 索引,应检查相关
reltuples值是否合理。 - 如果
btree_gist用于浮点或 bit 类型,可能需要重建索引。 - 如果使用
ltree存储非常长的路径,也可能需要重建索引。
可以在变更后运行针对业务表的检查,并根据发布说明决定是否执行重建。重建索引可能消耗大量磁盘、CPU 和 IO,应该纳入维护计划,而不是在业务高峰期临时操作。
补丁范围不只是数据库服务器
只升级 PostgreSQL server binary 并不代表整个 PostgreSQL 技术栈已经完成修复。客户端库、扩展和 contrib 模块同样可能包含安全漏洞。
例如,2025 年 11 月修复过 libpq 中的整数溢出问题 CVE-2025-12818,问题位于客户端库,而不是服务器端。2026 年 8 月的发布还涉及 pgcrypto、pg_stat_statements 和 PL/Perl 等组件。
补丁清单至少应覆盖:
- PostgreSQL server binary
libpq和应用使用的驱动程序- 连接池,例如 PgBouncer
contrib模块和扩展- 备份、监控和迁移工具
- 容器镜像及其基础操作系统包
一个已经修复的 PostgreSQL 服务器,如果仍然和存在漏洞的旧客户端库通信,整体风险并没有完全消失。补丁延迟应从“漏洞影响的组件恢复到已修复版本”开始计算,而不是只看数据库主机的包版本。
版本过期会让补丁延迟变成无限大
运行已经停止接收安全修复的 major version,是让补丁延迟变成无限大的确定性方法。
PostgreSQL 14 计划在 2026 年 11 月 12 日迎来最后一轮修复。此次 28 个 CVE 已经覆盖到 14.24,因此仍有窗口完成当前补丁并规划迁移到受支持的 major version。维护结束后,PostgreSQL 14 中新发现的问题不会再获得官方修复。
版本生命周期和补丁节奏其实是同一项工程管理工作:
- 小版本更新解决当前已知问题。
- Major version 迁移保证未来还能持续获得修复。
- 备份恢复演练保证出现问题时能够回到可运行状态。
补丁前最好准备一个真正测试过的恢复路径。备份是否存在并不等于可以恢复;只有实际完成恢复演练,并知道真实恢复时间,团队才知道补丁失败时能否接受其后果。
本周可以执行的清单
针对这次发布,可以按以下顺序处理:
- 将生产版本更新到
18.6、17.11、16.15、15.19或14.24,具体版本取决于当前 major version。 - 在 staging 环境验证应用连接、扩展和关键查询。
- 阅读发布说明的
Updating部分,检查是否需要额外维护。 - 优先升级备用节点,然后执行计划切换。
- 更新原主节点以及所有相关客户端、连接池和扩展。
- 检查复制状态、错误日志、连接数、延迟和业务指标。
- 记录本次补丁耗时,形成下一次 SLA 的基线。
- 为远程代码执行、公开 PoC 和高危漏洞分别定义明确的完成期限。
对于单节点环境,补丁可能需要一次短暂重启;对于具备备用节点和成熟故障切换流程的集群,可以将用户可见中断压缩到很短。无论采用哪种架构,最重要的指标都不是“我们知道有补丁”,而是“补丁发布后多久已经在实际生产流量上生效”。