4. 连接与网络层安全加固

数据库安全的第一道防线并不在表、视图或权限系统里,而在“谁能通过网络连到 PostgreSQL 实例”这一层。连接与网络层加固的目标可以概括为三件事:缩小暴露面(只监听必要地址)、保护传输通道(强制加密与身份校验)、控制连接来源与数量(防火墙与连接池)。本节围绕这三点展开,并给出可直接参考的配置与验证方法。

一、listen_addresses:先决定实例“听”在哪里

PostgreSQL 默认只监听本机回环地址,这是安全的默认值。参数 listen_addresses 决定实例在哪些网络接口上接受 TCP 连接。常见取值有三类:'localhost'(仅本机)、'*'(所有接口)、以及显式列出地址如 '127.0.0.1,10.0.20.15'。生产环境应避免直接使用 '*',而是绑定到内网业务网卡地址,让实例在公网或管理网段上不可见。

需要特别区分两个层次:listen_addresses 只决定“是否监听某个接口”,而“谁可以连、用什么认证方式连”由 pg_hba.conf 决定。二者必须配合:即使监听了内网地址,如果 pg_hba.conf 写成 host all all 0.0.0.0/0 md5,仍然等于对全网开放。一个更收敛的写法是按网段和用户限定,例如只允许应用网段以特定账号连接业务库:

# postgresql.conf
listen_addresses = '127.0.0.1,10.0.20.15'
port = 5432
ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file  = 'server.key'

# pg_hba.conf(顺序自上而下匹配,先匹配先生效)
# TYPE  DATABASE  USER      ADDRESS         METHOD
host    appdb     app_user  10.0.20.0/24    scram-sha-256
host    all       all       127.0.0.1/32    scram-sha-256
hostssl all       all       10.0.30.0/24    scram-sha-256
host    all       all       0.0.0.0/0       reject

注意最后一条 reject 作为兜底,能防止前面规则遗漏时被默认放行。修改后需 SELECT pg_reload_conf(); 或重启生效,并用 SHOW listen_addresses; 确认。

二、SSL/TLS 配置:把明文连接变成加密连接

PostgreSQL 原生支持 TLS。开启 ssl = on 后,客户端可通过 sslmode 选择加密强度。关键点是:服务端开启 SSL 不等于强制加密,客户端仍可能以明文连接。要真正强制,应在 pg_hba.conf 中使用 hostssl 而非 host,让非加密连接直接被拒绝。

客户端 sslmode 的常见取值与安全含义如下:disable 完全不加密;allow/prefer 优先明文或优先加密,均不校验证书;require 强制加密但不验证证书,可防窃听但防不了中间人;verify-ca 校验服务端证书由受信 CA 签发;verify-full 在此基础上再校验主机名,是最高等级。生产环境推荐 verify-full。

# 客户端连接示例(强制加密并校验主机名)
psql "host=db.internal port=5432 dbname=appdb user=app_user \
      sslmode=verify-full sslrootcert=/etc/pki/ca.crt"

# 查看当前连接是否加密
SELECT ssl, version, cipher FROM pg_stat_ssl WHERE pid = pg_backend_pid();

若查询返回 ssl = t 并显示 TLS 版本与加密套件,说明通道已加密;返回 f 则说明当前是明文连接,需要检查 pg_hba.conf 是否误用了 host。

三、证书管理:签发、权限与轮换

服务端证书需满足两个硬性条件:私钥文件权限必须为 0600 且属主为数据库运行用户,否则 PostgreSQL 会拒绝启动并报权限错误;证书的 CN 或 SAN 必须与客户端连接时使用的主机名一致,否则 verify-full 会失败。典型签发流程是:生成私钥与 CSR,由内部 CA 签发,部署 server.crt 与 server.key,并设置权限。

openssl req -new -nodes -text -out server.csr \
  -keyout server.key -subj "/CN=db.internal"
openssl x509 -req -in server.csr -text -days 365 \
  -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
chmod 600 server.key && chown postgres:postgres server.key

证书有有效期,必须规划轮换。轮换时先替换文件、再 pg_reload_conf(),新连接即使用新证书,已有连接不受影响,从而实现平滑过渡。建议在监控中对证书剩余有效期设置告警阈值(如 30 天)。

四、连接池安全与防火墙策略

连接池(如 PgBouncer)在降低连接开销的同时,也引入了新的安全边界。要点包括:池子监听地址同样应绑定内网;auth_type 使用 scram-sha-256 而非 trust;管理控制台 admin_users 严格限定;pool_mode 选择需注意,transaction 模式下会话级状态(如 SET、临时表、LISTEN)可能被串用,涉及行级安全或会话变量的场景应谨慎。此外,池到后端数据库的连接也应启用 TLS,避免“前端加密、后端明文”的假安全。

防火墙层面,应遵循最小放行原则:仅允许应用服务器网段访问 5432,管理访问走跳板机或专用管理网段,公网一律拒绝。云环境还需叠加安全组与网络 ACL。下面这张图展示了从客户端到数据库的完整加固链路与各层控制点。

连接与网络层加固链路 客户端 / 应用 sslmode=verify-full 携带 CA 根证书 防火墙 / 安全组 仅放行应用网段 公网 5432 拒绝 连接池 PgBouncer scram-sha-256 认证 后端连接亦启用 TLS PostgreSQL 实例 listen_addresses 绑定内网 ssl=on + hostssl 强制加密 各层控制点与验证方法 监听层:listen_addresses 绑定内网地址,SHOW listen_addresses 确认;避免使用 '*'。 访问控制:pg_hba.conf 用 hostssl + scram-sha-256,末尾加 reject 兜底,pg_reload_conf 生效。 传输加密:ssl=on,客户端 verify-full;SELECT ssl,cipher FROM pg_stat_ssl 验证是否加密。 证书管理:server.key 权限 0600,CN/SAN 与主机名一致,监控有效期并平滑轮换。 连接池与防火墙:池监听内网、认证加密、后端 TLS;防火墙仅放行必要网段与端口。

最后给出一个可执行的加固检查清单,便于逐项核对:

检查项期望结果验证方式
监听地址仅内网与回环SHOW listen_addresses;
访问规则hostssl + scram-sha-256,末尾 reject查看 pg_hba.conf 并重载
传输加密当前连接 ssl = tpg_stat_ssl 查询
私钥权限0600,属主 postgresls -l server.key
证书有效期剩余 > 30 天openssl x509 -enddate
防火墙仅应用网段可达 5432从非授权主机测试连接被拒
常见误区:只开启 ssl = on 就认为“已加密”。实际上客户端仍可用 sslmode=disable 明文连接,必须配合 hostssl 规则才能真正强制加密。

把上述五层控制点串起来,就形成了从网络入口到数据库进程的纵深防御:防火墙缩小可达范围,连接池收敛连接并统一认证,TLS 保护传输内容,证书体系保证对端可信,而 listen_addresses 与 pg_hba.conf 共同决定实例最终对谁可见、以何种方式可见。