PostgreSQL的连接安全由两层机制共同控制:一层是数据库自身的pg_hba.conf认证文件,另一层是操作系统防火墙。只改其中一层,往往会出现连接时快时慢、或者干脆报FATAL错误的情况。本文将从pg_hba.conf的规则语法入手,逐步讲解白名单的配置方法、认证方式的选择,以及与系统防火墙配合的完整方案。

一、理解pg_hba.conf的规则结构
pg_hba.conf是PostgreSQL的客户端认证配置文件,文件中的每一行代表一条规则,称为HBA(host-based authentication)条目。PostgreSQL收到连接请求时,会从文件第一行开始逐行匹配,一旦命中某条规则就立即使用该规则的认证方式,后续规则不再参与判断。这个匹配顺序非常关键,很多看似配置正确却无法连接的问题,根源都在规则顺序上。
每条规则由五个字段组成,格式如下:
# 类型 数据库 用户 地址 认证方式 host all all 192.168.1.0/24 scram-sha-256
类型字段决定了规则的适用场景:local匹配Unix域套接字连接(本机psql默认走这种方式),host匹配普通的TCP/IP明文连接,hostssl只匹配SSL加密连接,hostnossl则明确拒绝SSL连接。生产环境建议只保留hostssl或至少配置强认证的host规则。地址字段支持CIDR格式的网段,例如192.168.1.0/24表示整个C类网段,也可以写单个IP如10.0.0.5/32。IPv6地址同样支持,写法类似fe80::/10。
配置完成后必须让服务重新加载规则,直接重启会中断现有连接,推荐使用reload方式:
# 方式一:使用pg_ctl pg_ctl reload -D /var/lib/pgsql/16/data # 方式二:使用SQL命令(推荐,无需知道数据目录位置) psql -U postgres -c "SELECT pg_reload_conf();"
文件位置可以通过查询SHOW hba_file;获得,不同发行版和安装方式下路径差异较大,例如源码编译默认在/usr/local/pgsql/data下,而CentOS的RPM包通常放在/var/lib/pgsql/16/data目录中。
二、认证方式的选择与白名单实战
认证方式决定了客户端命中规则后如何证明身份。trust方式完全不验证密码,任何能连上端口的客户端都可以以任意用户身份登录,除非是本机测试环境,否则绝对不要对host类型规则使用trust。md5是老版本的默认方式,使用双向哈希质询,安全性已经不能满足现代要求。scram-sha-256是PostgreSQL 10之后推荐的认证方式,支持通道绑定,能有效抵御中间人攻击。
一个典型的生产环境白名单配置如下:
# TYPE DATABASE USER ADDRESS METHOD # 本机套接字连接,使用对等认证 local all all peer # 本机TCP连接 host all all 127.0.0.1/32 scram-sha-256 host all all ::1/128 scram-sha-256 # 应用服务器网段,只允许访问业务库 host shopdb app_user 192.168.10.0/24 scram-sha-256 # 运维跳板机单个IP,拥有全部库权限 host all dba_admin 172.16.5.8/32 scram-sha-256 # 拒绝其他一切连接(放在最后一行兜底) host all all 0.0.0.0/0 reject
这份配置体现了白名单设计的核心思想:先放行明确信任的来源,最后用reject规则拒绝所有未列出的地址。注意reject必须放在最后,因为规则是按顺序匹配的,如果放在前面会把合法连接也一并拒绝。数据库字段和用户字段支持all关键字,也支持逗号分隔的多个值,还可以配合/etc/postgresql/16/main/pg_ident.conf实现操作系统用户与数据库用户的映射。
切换认证方式还有一个隐藏的坑:如果已有用户的密码是按md5格式存储的,直接把规则改成scram-sha-256后,旧用户将无法登录。需要先为用户重新设置密码,让密码以SCRAM格式存储:
-- 查看密码存储格式 SELECT rolname, rolpassword FROM pg_authid WHERE rolname = 'app_user'; -- 重新设置密码,按password_encryption参数的算法加密 SET password_encryption = 'scram-sha-256'; ALTER USER app_user WITH PASSWORD '新的强密码';
三、系统层防火墙与双层防护配置
pg_hba.conf只控制认证层面,如果攻击者连端口都摸不到,攻击成本会更高,这就是系统防火墙的价值。两层配合的原则是:系统防火墙做粗粒度的端口级过滤,pg_hba.conf做细粒度的用户和库级控制。以CentOS的firewalld为例,PostgreSQL默认使用5432端口,白名单配置如下:
# 只允许应用网段访问5432端口 firewall-cmd --permanent --new-zone=pgzone firewall-cmd --permanent --zone=pgzone --add-source=192.168.10.0/24 firewall-cmd --permanent --zone=pgzone --add-port=5432/tcp firewall-cmd --reload # 从public区域移除5432,防止默认放行 firewall-cmd --permanent --zone=public --remove-port=5432/tcp
使用iptables的环境可以直接写规则,注意插入顺序同样重要,拒绝规则要放在放行规则之后:
# 允许应用网段 iptables -A INPUT -p tcp --dport 5432 -s 192.168.10.0/24 -j ACCEPT # 允许运维跳板机 iptables -A INPUT -p tcp --dport 5432 -s 172.16.5.8 -j ACCEPT # 拒绝其余来源 iptables -A INPUT -p tcp --dport 5432 -j DROP # 保存规则使其重启后仍然生效 service iptables save
另外别忘了postgresql.conf中的listen_addresses参数。如果它的值还是默认的localhost,数据库根本不会监听外部网卡,防火墙和pg_hba.conf配置得再正确也无法远程连接。需要将其改为具体网卡IP或*,然后重启数据库生效。此外云服务器还要检查安全组规则,云平台安全组是第三层过滤,与系统防火墙独立工作,任何一层拦截都会导致连接失败。
四、常见连接故障排查思路
配置完成后连接被拒时,不要盲目改动规则,先看报错信息。no pg_hba.conf entry for host说明请求到达了数据库但没有命中任何允许规则,重点检查客户端实际出口IP与规则中的地址段是否匹配,可以通过报错信息中给出的host地址确认。 password authentication failed说明命中了规则但密码或认证格式不对,对照前文提到的密码存储格式排查即可。
排查工具方面,ss -tlnp | grep 5432确认监听地址,telnet 数据库IP 5432或nc -zv 数据库IP 5432测试端口连通性,数据库日志中会记录每一次被拒绝的连接及命中的规则行号。建议每次修改只动一处并立即验证,配合版本管理工具保存pg_hba.conf的变更历史,这样回滚和审计都有据可查。多层白名单虽然配置步骤多一些,但每一层职责清晰,排查时按网络、防火墙、认证的顺序逐层检查,问题定位会非常高效。
PostgreSQL防火墙白名单pg_hba.conf修改时间:2026-08-31 04:16:42