PostgreSQL 密码算法从 md5 迁移至 scram-sha-256 的影响分析与升级方案

文章目录

  • [PostgreSQL 密码算法从 md5 迁移至 scram-sha-256 的影响分析与升级方案](#PostgreSQL 密码算法从 md5 迁移至 scram-sha-256 的影响分析与升级方案)
    • [场景 1](#场景 1)
  • 场景2
    • 核心矛盾
    • 必须额外做的事
      • [1. 升级脚本:重置所有可登录用户的密码](#1. 升级脚本:重置所有可登录用户的密码)
      • [2. 对于未知密码的业务用户](#2. 对于未知密码的业务用户)
      • [3. 完整升级流程(推荐)](#3. 完整升级流程(推荐))
    • 风险清单
    • 升级脚本模板

PostgreSQL 密码算法从 md5 迁移至 scram-sha-256 的影响分析与升级方案

场景 1

分析

阶段 password_encryption pg_hba.conf 认证方式 存储的密码哈希 是否正常
PG 15.13 未设置(PG15 默认 scram-sha-256 md5 SCRAM-SHA-256 正常:md5 认证方式允许同时验证 md5 和 SCRAM-SHA-256 哈希
PG 15.18 md5 md5 SCRAM-SHA-256(未变) 正常:password_encryption 只影响新设置的密码,不会回溯重加密已有密码
改为 scram-sha-256 scram-sha-256 scram-sha256 SCRAM-SHA-256(未变) 正常:哈希本身就是 SCRAM-SHA-256,认证方式匹配

关键原理

  1. password_encryption 仅影响后续通过 ALTER USER / CREATE USER 设置的密码,不会自动重加密已有密码

  2. pg_hba.conf 中 md5 认证方式(PG 10+)实际是"md5 或 scram-sha-256 均可",会根据 pg_authid 中存储的哈希前缀自动选择

  3. 改为 scram-sha256 后,只有 SCRAM-SHA-256 哈希能通过认证------当前 postgres 用户的哈希恰好已是 SCRAM-SHA-256,所以不受影响


等级保护合规风险

风险点 说明
其他用户可能是 md5 哈希 如果库中存在 md5 前缀的哈希(SELECT rolname, rolpassword FROM pg_authid WHERE rolpassword LIKE 'md5%'),改为 scram-sha256这些用户将无法登录
需强制重置所有 md5 密码 合规要求:所有密码必须用 scram-sha-256 存储。需逐个 ALTER USER xxx PASSWORD '新密码' 重置

建议操作

sql 复制代码
-- 1. 检查是否有 md5 哈希的用户
SELECT rolname, rolpassword FROM pg_authid 
WHERE rolpassword LIKE 'md5%' AND rolcanlogin = true;

-- 2. 对每个 md5 用户重置密码(重置后自动用当前 password_encryption=scram-sha-256 加密)
ALTER USER xxx PASSWORD '<新密码>';

-- 3. 验证全部为 scram-sha-256
SELECT rolname, rolpassword FROM pg_authid 
WHERE rolpassword IS NOT NULL AND rolcanlogin = true;

场景2

环境比较新, 比如环境是 D007及之后的版本(多数局点), 最开始 password_encryption 就是 md5,且 pg_hba.conf 中auth_type 也是 md5 假设现在要将该需求合入 D013 中(将 password_encryption 改为 scram-sha256, 将 pg_hba.conf 中 auth_type 改为 scram-sha256, 同时期望存储的密码也是 scram-sha-256 加密的), 则 对于从 D007升级到 D013 的环境, 需要关注 password_encryption 的 变动导致 postgres 等用户登陆的影响 有啥需要额外做的 以实现该需求吗? 这是个经典的 PG 密码算法迁移问题。从 D007(md5)升级到 D013(scram-sha-256),必须额外做密码迁移,否则所有用户登录失败


核心矛盾

plaintext 复制代码
D007 现状:
  password_encryption = md5
  pg_hba.conf auth_type = md5
  pg_authid 中存储: md5xxxxxxxxxxxx(md5 哈希前缀)

D013 目标:
  password_encryption = scram-sha-256
  pg_hba.conf auth_type = scram-sha256
  要求 pg_authid 中存储: SCRAM-SHA-256$...(SCRAM 哈希前缀)

关键scram-sha256 认证方式只接受 SCRAM-SHA-256 哈希 ,md5 哈希的用户直接登录失败 。且 md5 哈希不可逆,无法转换为 SCRAM-SHA-256,必须用明文重新设置。


必须额外做的事

1. 升级脚本:重置所有可登录用户的密码

sql 复制代码
-- 升级前:检查受影响用户(密码以 md5 开头的可登录用户)
SELECT rolname, rolpassword 
FROM pg_authid 
WHERE rolpassword LIKE 'md5%' AND rolcanlogin = true;

已知明文密码的系统账户(postgres、replication 用户等),直接重置:

sql 复制代码
-- 先确保 password_encryption 已改为 scram-sha-256(影响新设置的密码用 SCRAM 加密)
-- 在 postgresql.conf 中: password_encryption = scram-sha-256
-- 执行 pg_ctl reload 或 SELECT pg_reload_conf();

-- 重置系统账户密码(用原明文重新设置,存储自动变为 SCRAM-SHA-256)
ALTER USER postgres PASSWORD '<系统管理员密码>';
ALTER USER replicator PASSWORD '<复制用户密码>';
-- ... 其他已知密码的系统账户

2. 对于未知密码的业务用户

有三种策略,按安全要求选择:

策略 做法 优点 缺点
A. 强制重置 升级后业务用户首次登录强制改密码 最安全,合规 影响业务,需协调
B. 临时兼容 pg_hba.conf 中先保留 md5,逐步迁移 零业务中断 过渡期不合规
C. 预先收集 升级前从应用配置中提取所有数据库连接密码,升级脚本中统一重置 一次性完成 需要梳理所有应用密码配置

推荐策略 C(最实用):

python 复制代码
# 升级脚本伪代码
# 1. 从应用配置文件中提取所有数据库连接密码
# 2. 在 PG 中统一重置

known_passwords = {
    "postgres": "<系统管理员密码>",
    "app_user1": "<从应用配置提取>",
    "app_user2": "<从应用配置提取>",
    # ...
}

for user, pwd in known_passwords.items():
    execute_sql(f"ALTER USER {user} PASSWORD '{pwd}';")

3. 完整升级流程(推荐)

plaintext 复制代码
阶段1:密码迁移(pg_hba.conf 仍为 md5,保证兼容)
  ① 修改 password_encryption = scram-sha-256
  ② pg_ctl reload
  ③ 执行密码重置脚本(ALTER USER ... PASSWORD '明文')
  ④ 验证:SELECT rolname, rolpassword FROM pg_authid 
         WHERE rolpassword LIKE 'md5%' AND rolcanlogin = true;
     → 期望结果为空(所有用户已迁移到 SCRAM-SHA-256)

阶段2:切换认证方式
  ⑤ 修改 pg_hba.conf: md5 → scram-sha256
  ⑥ pg_ctl reload(或 restart)
  ⑦ 验证登录:psql -U postgres -d postgres

阶段3:验证
  ⑧ 业务应用连接验证
  ⑨ 复制连接验证(如适用)

风险清单

风险 影响 应对
遗漏用户 --- 未重置密码的用户升级后无法登录 业务中断 升级前完整扫描 pg_authid,确保无 md5 哈希残留
复制槽用户 --- replication 用户密码未同步修改 主从复制断开 升级脚本中包含 replication 用户,同步修改 primary_conninfo
应用硬编码 md5 --- 某些旧驱动/中间件只支持 md5 认证 连接失败 确认所有客户端驱动版本 ≥ PG 10(均支持 SCRAM-SHA-256)
回滚 --- 升级失败需回滚到 D007 密码哈希不可逆 回滚前备份 pg_authid,回滚时用 ALTER USER 恢复 md5 密码

升级脚本模板

bash 复制代码
#!/bin/bash
# D007 → D013 密码算法迁移脚本

PG_USER="postgres"
PG_HOST="127.0.0.1"
PG_PORT="5432"

echo "=== 阶段1:检查待迁移用户 ==="
MD5_USERS=$(psql -U $PG_USER -h $PG_HOST -p $PG_PORT -t -Ac \
    "SELECT rolname FROM pg_authid WHERE rolpassword LIKE 'md5%' AND rolcanlogin = true")

if [ -z "$MD5_USERS" ]; then
    echo "无 md5 用户,无需迁移"
else
    echo "待迁移用户: $MD5_USERS"
    echo "FATAL: 存在 md5 用户,必须先重置密码!"
    exit 1
fi

echo "=== 阶段2:重置系统账户密码 ==="
# password_encryption 已在 postgresql.conf 中设为 scram-sha-256
psql -U $PG_USER -h $PG_HOST -p $PG_PORT -c \
    "ALTER USER postgres PASSWORD '<系统管理员密码>';"
# ... 其他用户

echo "=== 阶段3:验证迁移结果 ==="
REMAINING=$(psql -U $PG_USER -h $PG_HOST -p $PG_PORT -t -Ac \
    "SELECT count(*) FROM pg_authid WHERE rolpassword LIKE 'md5%' AND rolcanlogin = true")
echo "剩余 md5 用户数: $REMAINING"

if [ "$REMAINING" -ne 0 ]; then
    echo "FATAL: 仍有用户未迁移!"
    exit 1
fi

echo "=== 阶段4:切换 pg_hba.conf ==="
# 修改 pg_hba.conf: md5 → scram-sha256
sed -i 's/\bmd5\b/scram-sha256/g' $PGDATA/pg_hba.conf
pg_ctl reload

echo "=== 迁移完成 ==="

总结 :额外必须做的是用明文重置所有 md5 用户的密码,仅改配置文件不够------存储的 md5 哈希不会自动变成 SCRAM-SHA-256