PostgreSQL默认监听5432端口且认证失败没有延迟机制,这使它成为互联网上自动化扫描和暴力破解的高频目标。攻击者通常利用弱口令、未限制来源IP以及默认超级用户postgres来尝试登录,一旦成功即可获得数据库完全控制权。要有效防护,需要从网络层、认证层、日志审计和主动阻断四个维度同时配置,而不是只改一个密码。

1. 优先处理网络暴露面:pg_hba.conf的精细化控制

PostgreSQL的客户端认证由pg_hba.conf文件控制,该文件按规则顺序匹配,第一条匹配的规则生效。默认安装往往包含类似“host all all 0.0.0.0/0 md5”的宽松规则,这等于向所有IP开放密码尝试。防护的第一步是删除或注释所有过宽的规则,改为仅允许业务所需的具体IP段或单IP。例如只允许内网应用服务器访问:

# TYPE  DATABASE  USER  ADDRESS          METHOD
host    all       app   192.168.10.0/24  scram-sha-256
host    all       all   127.0.0.1/32     scram-sha-256

如果数据库必须对公网提供服务,应使用VPN或专线收敛访问入口,而不是直接暴露5432端口。对于无法避免的公网访问,至少要将规则限制到业务合作方的固定IP,并拒绝所有其他来源。修改pg_hba.conf后需要执行pg_ctl reload或SELECT pg_reload_conf();使其生效。

2. 强制使用高强度密码认证方法

PostgreSQL 10及以上版本支持scram-sha-256认证,它比旧的md5方法更安全,能抵抗离线字典攻击和重放攻击。在pg_hba.conf中将所有host规则的METHOD改为scram-sha-256,然后在postgresql.conf中设置password_encryption = scram-sha-256。已有用户的密码哈希需要重新设置才会升级为SCRAM格式,可以通过ALTER USER username WITH PASSWORD '新密码';来更新。

同时应禁用trust认证方式,尤其是在TCP连接上。trust意味着无需密码即可登录,任何能连到端口的客户端都能直接进入数据库。检查pg_hba.conf中是否存在method为trust的非本地规则,如有必须立即改为scram-sha-256或至少md5。

3. 锁定默认超级用户并实施最小权限

postgres是PostgreSQL安装后自带的超级用户,也是暴力破解的首选目标。即使密码足够复杂,也不应该让远程客户端直接使用postgres登录。建议创建一个非超级用户作为日常运维账号,并仅授予其所需数据库的权限。对于postgres超级用户,在pg_hba.conf中将其远程登录规则全部删除,只保留本地Unix socket或本地回环访问:

local   all   postgres   peer
host    all   postgres   127.0.0.1/32   scram-sha-256

这样即使攻击者获取了postgres的密码,也无法从远程建立连接。日常管理操作可以通过本地登录后再切换角色,或者使用其他受限账号执行。

4. 启用连接延迟与失败处理参数

PostgreSQL本身没有内置像MySQL那样的连接失败延迟插件,但可以通过两个参数间接增加暴力破解成本。在postgresql.conf中设置:

authentication_timeout = 10s

该参数控制客户端完成认证握手的最长时间,默认60秒,缩短到10秒可以让自动化工具在慢速网络下更容易超时失败。另一个关键参数是:

log_connections = on
log_disconnections = on

开启连接日志后,每一次成功或失败的连接尝试都会记录来源IP、用户名和结果,为后续的主动阻断提供数据基础。

5. 利用系统防火墙实现动态封禁

单靠PostgreSQL自身无法自动封禁暴力破解来源IP,需要借助操作系统层面的工具。Linux下最常用的方案是fail2ban。安装后创建一个针对PostgreSQL的jail配置文件:

[postgresql]
enabled = true
filter = postgresql
logpath = /var/log/postgresql/postgresql.log
maxretry = 5
findtime = 300
bantime = 3600
action = iptables-multiport[name=postgresql, port="5432", protocol=tcp]

对应的filter需要匹配PostgreSQL日志中的认证失败关键字。PostgreSQL的认证失败日志通常包含“password authentication failed for user”或“FATAL”。filter文件内容示例:

[Definition]
failregex = ^.*password authentication failed for user .*$
            ^.*no pg_hba.conf entry for host .*$
ignoreregex =

这样fail2ban会在5次失败后自动将来源IP加入iptables拒绝列表,持续封禁1小时。对于使用firewalld的系统,action可改为firewallcmd-rich-rules。需要注意的是,PostgreSQL日志格式可能因版本和日志配置不同而有差异,部署后应先用fail2ban-regex测试正则匹配是否准确。

6. 修改默认端口与隐藏版本信息

将PostgreSQL的监听端口从默认5432改为非标准端口,可以过滤掉大部分无差别扫描。在postgresql.conf中设置:

port = 15432

同时建议将unix_socket_directories保持默认,仅修改TCP端口。修改后需要重启数据库服务。虽然端口修改不是真正的安全措施,但能显著降低自动化攻击的命中率。另外,PostgreSQL在连接建立时会返回版本号,攻击者可据此寻找对应版本漏洞。可以通过在postgresql.conf中设置:

update_process_title = off

来减少进程信息暴露,但版本号本身无法完全隐藏。更实际的做法是保持数据库及时更新小版本补丁,避免已知漏洞被利用。

7. 开启详细审计日志并设置告警

完整的日志记录是发现和追溯暴力破解的基础。在postgresql.conf中建议配置:

logging_collector = on
log_directory = 'pg_log'
log_filename = 'postgresql-%Y-%m-%d.log'
log_statement = 'ddl'
log_min_error_statement = error
log_connections = on
log_disconnections = on
log_line_prefix = '%m [%p] %q%u@%d %h %a '

其中%h会记录客户端IP地址,%u记录用户名,%m记录时间戳。通过分析这些日志,可以统计出高频失败登录的来源IP和尝试的用户名。建议将日志接入集中日志平台,并设置规则:同一IP在5分钟内出现超过10次认证失败即触发告警。对于生产环境,还可以开启log_statement = 'mod'来记录所有数据变更语句,便于事后审计。

8. 使用SSL加密传输防止密码嗅探

即使认证方式使用了scram-sha-256,如果传输层不加密,密码哈希仍可能被中间人截获。PostgreSQL支持SSL加密连接,需要在postgresql.conf中开启:

ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'

生成自签名证书或使用内部CA签发证书后,在pg_hba.conf中使用hostssl规则替代host规则:

hostssl all app 192.168.10.0/24 scram-sha-256

这样只有SSL加密的连接才能匹配该规则,明文连接会被直接拒绝。对于公网环境,SSL是必须项,否则密码和查询数据都可能被监听。

9. 定期审查用户与权限配置

暴力破解成功的前提是存在可被利用的账号。定期执行以下SQL检查所有角色及其权限:

SELECT rolname, rolcanlogin, rolsuper, rolconnlimit FROM pg_roles WHERE rolcanlogin = true;

重点检查是否有非必要的登录角色、是否有超级用户权限被滥用、是否有角色没有设置连接数限制。对于业务账号,设置rolconnlimit可以限制单个账号的并发连接数,防止攻击者用单个账号建立大量连接拖垮数据库。同时删除或禁用长期不用的账号,减少可被猜测的目标数量。

10. 配置操作系统级别的资源限制

在Linux系统上,可以通过systemd或limits.conf限制postgres用户可打开的文件数和进程数,防止暴力破解导致连接耗尽。在/etc/security/limits.conf中添加:

postgres soft nofile 65535
postgres hard nofile 65535
postgres soft nproc 4096
postgres hard nproc 4096

同时在postgresql.conf中设置max_connections为一个合理值,不要设置过大。默认100通常足够中小型应用,过大反而会让攻击者有更多并发尝试的空间。对于每个数据库可以设置:

ALTER DATABASE dbname WITH CONNECTION LIMIT 20;

限制单个数据库的最大连接数,防止暴力破解尝试消耗全部连接资源。

PostgreSQL的防暴力破解是一个多层防护体系,核心在于减少暴露面、提高破解成本、加快发现速度。网络层用pg_hba.conf和防火墙控制谁能连,认证层用scram-sha-256和强密码保证连上后难以猜中,日志层用详细审计和fail2ban实现自动封禁,最后用SSL加密防止传输层攻击。这些配置相互配合,任何单点措施都不足以应对持续演变的暴力破解工具。实际部署时应根据业务环境逐项落实,并定期检查日志和规则有效性。