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。下面这张图展示了从客户端到数据库的完整加固链路与各层控制点。
最后给出一个可执行的加固检查清单,便于逐项核对:
| 检查项 | 期望结果 | 验证方式 |
|---|---|---|
| 监听地址 | 仅内网与回环 | SHOW listen_addresses; |
| 访问规则 | hostssl + scram-sha-256,末尾 reject | 查看 pg_hba.conf 并重载 |
| 传输加密 | 当前连接 ssl = t | pg_stat_ssl 查询 |
| 私钥权限 | 0600,属主 postgres | ls -l server.key |
| 证书有效期 | 剩余 > 30 天 | openssl x509 -enddate |
| 防火墙 | 仅应用网段可达 5432 | 从非授权主机测试连接被拒 |
ssl = on 就认为“已加密”。实际上客户端仍可用 sslmode=disable 明文连接,必须配合 hostssl 规则才能真正强制加密。把上述五层控制点串起来,就形成了从网络入口到数据库进程的纵深防御:防火墙缩小可达范围,连接池收敛连接并统一认证,TLS 保护传输内容,证书体系保证对端可信,而 listen_addresses 与 pg_hba.conf 共同决定实例最终对谁可见、以何种方式可见。