暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

PostgreSQL 修复 28 个安全漏洞:这份生产升级清单 DBA 可以直接用

原创 三笠丶 23小时前
29

本文导读

PostgreSQL 在 8 月 13 日一次修复 28 个安全漏洞和 110 多个 Bug。本文不逐条翻译 CVE,而是提供升级优先级、巡检 SQL、主备验证、回退条件和完整变更清单,DBA 可以直接用于生产升级准备。

8 月 13 日,PostgreSQL 一口气发布了 18.6、17.11、16.15、15.19 和 14.24。

这次更新修复了 28 个安全漏洞,还有 110 多个 Bug。消息出来以后,DBA 面临的问题不是“要不要下载补丁”,而是生产库什么时候升、先升哪些、怎么证明升级已经做完。

这几个问题不解决,公告看得再仔细,最后还是要从头写变更方案。

所以这篇文章不准备逐条翻译 CVE。我把官方公告中真正会影响生产变更的内容拆开,整理成一套升级前检查、升级顺序和升级后验收清单。文中的 SQL 可以直接执行,最后一张表也可以复制到变更单里。

先说结论:支持版本都应该尽快升级,但不要所有库一起冲。客户端工具也在本轮漏洞范围内,升级后还有 GIN、btree_gistltree 三类对象需要额外检查。PostgreSQL 14 则要多做一件事,把大版本迁移计划一起定下来。

先定优先级,哪些库应该排在前面

PostgreSQL 安全更新从资产判断到升级后验收的流程图

先将资产和漏洞条件对应起来,再安排测试、分批升级与升级后验收。
28 个漏洞看着挺吓人,但只按漏洞数量安排窗口没有意义。

官方披露的问题分布在核心服务、客户端、过程语言和扩展模块中。多项 CVSS v3.1 评分达到 8.8,涉及 pg_dumppsql、正则表达式、to_charpg_stat_statementsfuzzystrmatch 等路径。逻辑解码、类型 USAGE 权限、行级安全缓存,以及 GSSAPI 配合 SSL 使用时的加密约束也有修复。

换到生产环境里,可以按下面的顺序排:

优先级 环境特征 建议
P0 有公网或跨网入口、低权限用户较多、外部人员可提交 SQL 完成验证后优先升级
P1 使用逻辑复制、过程语言、受影响扩展,或大量使用 pg_dumppsql 紧随 P0 安排
P1 核心生产主备、监管或敏感数据环境 按业务窗口尽快分批升级
P2 仅内网访问、账号严格受控、攻击条件较少 不免升级,可稍后排期
单独立项 PostgreSQL 14 先升 14.24,同时启动大版本迁移

“只在内网运行”只能降低一部分风险,不能直接作为不升级的理由。备份服务器、运维终端、扩展和复制链路都可能进入本轮影响范围。

这里还有一个很容易漏的地方:客户端。

pg_dump 有堆缓冲区溢出问题,psql 也在漏洞清单中。只升级数据库服务器,不检查备份机、跳板机、容器镜像和运维电脑,风险并没有完全收掉。资产清单里必须同时记录服务端和客户端版本。

Linux 主机可以先查出命令来自哪里:

type -a psql pg_dump psql --version pg_dump --version

如果备份任务运行在容器中,还要检查实际使用的镜像,而不是只看宿主机。

升级前先跑这组检查

小版本升级本身并不复杂。官方说明不需要执行 pg_upgrade,也不用导出再导入,停止数据库、更新二进制文件、重新启动即可。

真正费时间的是升级前确认。

下面这组 SQL 建议在每套环境保存一份结果,升级后再跑一次做对比。

1. 记录版本与运行状态

SELECT version(); SELECT current_setting('server_version_num') AS server_version_num, pg_postmaster_start_time() AS instance_start_time, pg_is_in_recovery() AS is_standby;

2. 盘点已安装扩展

SELECT extname, extversion FROM pg_extension ORDER BY extname;

重点关注 btree_gistltreepg_stat_statementsfuzzystrmatchpgcrypto,以及当前环境自行安装的第三方扩展。数据库二进制升级后,第三方扩展是否兼容,仍需按各自厂商或项目文档确认。

3. 盘点可登录账号

SELECT rolname, rolsuper, rolcreaterole, rolcreatedb, rolreplication, rolbypassrls FROM pg_roles WHERE rolcanlogin ORDER BY rolsuper DESC, rolname;

这不是为了临时删账号,而是确认哪些漏洞利用条件可能在当前环境成立。账号越多、权限边界越复杂,升级优先级越高。

4. 检查逻辑复制对象

SELECT slot_name, slot_type, plugin, database, active FROM pg_replication_slots ORDER BY slot_name; SELECT subname, subenabled, subslotname FROM pg_subscription ORDER BY subname;

pg_subscription 的查看权限受限,建议使用具备相应权限的管理账号执行。没有逻辑复制时,结果为空即可。

5. 保存主库复制基线

SELECT application_name, client_addr, state, sync_state, sent_lsn, write_lsn, flush_lsn, replay_lsn, write_lag, flush_lag, replay_lag FROM pg_stat_replication ORDER BY application_name;

这些结果升级后还要再查。不要只截图一个“streaming”,LSN 和延迟一起留着更好对比。

三类对象必须单独检查

PostgreSQL 升级后的 GIN、btree_gist 和 ltree 检查图

三类对象都有明确触发条件,检查命中情况后再决定是否执行 ANALYZE 或 REINDEX。
本轮公告最特别的地方,是官方明确列出了三个升级后可能需要处理的问题。

GIN 索引:检查 reltuples

之前并行构建 GIN 索引时,Bug 可能把表在 pg_class 中的 reltuples 留成 InfinityNaN。这个值异常后,autovacuum 和 autoanalyze 可能不再处理相应表,而且不会自己恢复。

升级后执行官方给出的 SQL:

SELECT DISTINCT t.oid::regclass AS table_name, t.reltuples FROM pg_class t JOIN pg_index i ON t.oid = i.indrelid JOIN pg_class ic ON i.indexrelid = ic.oid WHERE t.relhasindex AND ic.relam = 2742 ORDER BY 1;

如果发现 reltuplesInfinityNaN,或者与实际数据量明显不符,对相应表执行:

ANALYZE schema_name.table_name;

不要见到 GIN 索引就全部重建。官方建议是先检查 reltuples,发现异常后执行 ANALYZE,或者通过创建索引重置该值。

btree_gist:找出可能受影响的索引

btree_gist 涉及两类情况:float4float8 列中可能存在 NaN,以及 bitbit varying 列。

先确认扩展是否安装:

SELECT extname, extversion FROM pg_extension WHERE extname = 'btree_gist';

再列出建在这些数据类型上的 GiST 索引,作为人工核对范围:

SELECT DISTINCT n.nspname AS schema_name, idx.relname AS index_name, tbl.relname AS table_name, a.attname AS column_name, format_type(a.atttypid, a.atttypmod) AS data_type, pg_get_indexdef(idx.oid) AS index_def FROM pg_index i JOIN pg_class idx ON idx.oid = i.indexrelid JOIN pg_class tbl ON tbl.oid = i.indrelid JOIN pg_namespace n ON n.oid = tbl.relnamespace JOIN pg_am am ON am.oid = idx.relam JOIN pg_attribute a ON a.attrelid = tbl.oid AND a.attnum = ANY(i.indkey) WHERE am.amname = 'gist' AND a.atttypid IN ( 'float4'::regtype, 'float8'::regtype, 'bit'::regtype, 'varbit'::regtype ) ORDER BY 1, 2, 4;

这条 SQL 用于缩小检查范围,最终还要结合 index_def 确认索引是否使用 btree_gist 提供的操作符类。命中官方条件的索引,升级后执行:

REINDEX INDEX schema_name.index_name;

生产环境执行前要评估锁、额外空间和 I/O。是否改用 REINDEX CONCURRENTLY,需要结合 PostgreSQL 版本、索引类型和业务窗口决定,不能只为了减少阻塞就直接替换命令。

ltree:大多数库不会命中,但要确认

ltree 的条件比较极端。只有包含大约 14653 个以上标签的超长值,B-tree 索引才可能受到影响。

先找出 ltree 列上的 B-tree 索引:

SELECT DISTINCT n.nspname AS schema_name, tbl.relname AS table_name, idx.relname AS index_name, a.attname AS column_name, pg_get_indexdef(idx.oid) AS index_def FROM pg_index i JOIN pg_class idx ON idx.oid = i.indexrelid JOIN pg_class tbl ON tbl.oid = i.indrelid JOIN pg_namespace n ON n.oid = tbl.relnamespace JOIN pg_am am ON am.oid = idx.relam JOIN pg_attribute a ON a.attrelid = tbl.oid AND a.attnum = ANY(i.indkey) WHERE am.amname = 'btree' AND a.atttypid = 'ltree'::regtype ORDER BY 1, 2, 3;

对查询结果中的列检查最大标签数:

SELECT max(nlevel(column_name)) AS max_labels FROM schema_name.table_name;

超过约 14653 时,升级后重建对应索引。没有安装 ltree 扩展的环境,类型转换会报不存在,可以直接跳过这一项。

主备环境怎么安排升级顺序

这轮更新还修复了一个影响 PostgreSQL 14、15 和 16 的回归问题。备库回放较旧小版本主库生成的 WAL 时,可能发生自死锁并停止推进。

因此,主备环境不能只验证数据库是否启动。

常见做法是先升级备库,再升级主库,可以缩短主库窗口,也方便先观察备库启动和回放情况。但具体顺序仍要看复制拓扑、包管理方式、自动故障转移组件和厂商要求。使用 Patroni、repmgr、云数据库或其他高可用平台时,先按对应产品的维护流程操作,不要把一套顺序硬套到所有环境。

升级后的主库检查:

SELECT application_name, client_addr, state, sync_state, sent_lsn, write_lsn, flush_lsn, replay_lsn, write_lag, flush_lag, replay_lag FROM pg_stat_replication ORDER BY application_name;

备库检查:

SELECT pg_is_in_recovery() AS is_standby, pg_last_wal_receive_lsn() AS receive_lsn, pg_last_wal_replay_lsn() AS replay_lsn, pg_last_xact_replay_timestamp() AS last_replay_time, now() - pg_last_xact_replay_timestamp() AS replay_delay; SELECT status, sender_host, sender_port, slot_name, latest_end_lsn, latest_end_time FROM pg_stat_wal_receiver;

如果备库没有新事务可回放,replay_delay 不能单独代表复制异常。最好在主库制造一条可控测试记录,确认对应 LSN 能够到达并完成回放。

升级后的验收,别停在 SELECT version()

数据库能启动只是第一关。

检查归档

SELECT archived_count, failed_count, last_archived_wal, last_archived_time, last_failed_wal, last_failed_time, stats_reset FROM pg_stat_archiver;

检查 autovacuum 与统计信息

SELECT schemaname, relname, n_live_tup, n_dead_tup, last_autovacuum, last_autoanalyze, autovacuum_count, autoanalyze_count FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 30;

GIN 索引对应表要重点看,避免 reltuples 异常导致自动维护一直不执行。

检查无效索引

SELECT n.nspname AS schema_name, c.relname AS index_name, i.indisvalid, i.indisready, pg_get_indexdef(c.oid) AS index_def FROM pg_index i JOIN pg_class c ON c.oid = i.indexrelid JOIN pg_namespace n ON n.oid = c.relnamespace WHERE NOT i.indisvalid OR NOT i.indisready ORDER BY 1, 2;

检查长事务与阻塞

SELECT pid, usename, application_name, state, wait_event_type, wait_event, now() - xact_start AS xact_age, left(query, 200) AS query FROM pg_stat_activity WHERE xact_start IS NOT NULL ORDER BY xact_start;

最后再验证业务连接、连接池、监控采集、定时任务和备份。备份任务不能只看“任务启动成功”,至少确认产生了有效备份文件,并按现有恢复演练制度验证可恢复性。

什么时候应该停止变更或回退

回退条件最好在变更前写清楚,不能等出问题后现场讨论。

出现以下情况时,应暂停后续批次并按既定方案处理:

  • 数据库或关键扩展无法正常加载;
  • 主备复制无法恢复,WAL 长时间不再推进;
  • 业务核心 SQL 出现可重复的错误结果或严重性能回退;
  • 连接池、认证或应用连接持续异常;
  • 归档、备份或监控链路无法恢复;
  • 索引处理时间、锁等待或额外空间超过变更预估。

小版本更新通常只替换二进制文件,但回退不等于随便把旧包装回去。包管理依赖、扩展文件、启动脚本、参数变化和故障转移状态都要提前确认。使用厂商发行版或云平台的,回退流程以对应产品文档为准。

这张表可以直接放进变更单

升级前

  • 服务端和客户端版本已经盘点,数据库、备份机、跳板机和容器均有记录。
  • 扩展与逻辑复制对象已经盘点,受影响组件和第三方扩展兼容性已经确认。
  • 主备、归档和备份基线已经保存,最近一次有效备份可以查到。
  • GIN、btree_gistltree 候选对象已经找出,处理计划已经确定。
  • 回退责任人、触发条件、操作命令和验证方法已经完成评审。

演练与生产升级

  • 类生产环境已经完成升级,应用、复制、扩展、监控和备份验证通过。
  • 生产环境按计划分批升级,前一批稳定后再进入下一批。

升级后

  • 目标版本正确,数据库日志中没有新增严重错误。
  • WAL 正常接收和回放,归档没有持续失败。
  • 命中条件的特殊对象已经完成 ANALYZEREINDEX
  • 连接池、定时任务、监控采集和备份任务均已恢复正常。

后续工作

  • PostgreSQL 14 已经建立升级到受支持大版本的迁移计划。

PostgreSQL 14 将在 2026 年 11 月 12 日停止维护。14.24 解决的是眼前这轮安全问题,不能延长大版本的生命周期。还在使用 14 的团队,最好把“小版本补洞”和“大版本迁移”拆成两个任务,同时推进。

这轮更新要不要升?要,而且应该尽快进入计划。

本文小结

这轮 PostgreSQL 更新应该尽快安排。升级前同时盘点服务端、客户端、扩展和复制对象,保存运行基线并写清回退条件;升级后处理命中条件的 GIN、btree_gist 与 ltree 对象,再验证主备、归档、连接池、监控和备份。PostgreSQL 14 还要另外建立大版本迁移计划。

参考资料

版本号正确,只能说明补丁装上了。主备、归档、备份和业务链路全部恢复正常,这个升级窗口才算真正结束。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论