PostgreSQL本身提供了丰富的安全机制,但默认配置往往偏向易用性而非安全性。如果不对认证方式、监听地址、权限分配和日志策略做针对性调整,数据库很容易成为攻击者的突破口。例如默认的pg_hba.conf可能允许本地trust认证,或者监听了所有网络接口但没有启用SSL,这使得数据库在内部网络中也能被未授权主机探测和连接。下面从认证、权限、加密、审计等多个维度展开说明如何系统性地加固PostgreSQL实例。

认证方式与访问控制加固
认证是数据库安全的第一道闸门。PostgreSQL通过pg_hba.conf文件控制客户端认证规则,默认安装可能包含类似host all all 127.0.0.1/32 trust的条目,这意味着本地回环地址上的所有连接无需密码即可通过。如果服务器被其他本地进程利用,或者攻击者通过SSH隧道转发到本地端口,这种配置会直接暴露数据库。因此第一步应当全面审查pg_hba.conf,将trust和password认证替换为更安全的scram-sha-256。password认证以明文形式发送密码,而scram-sha-256使用挑战-响应机制,即使网络流量被截获也无法还原出密码。
修改pg_hba.conf后需要重新加载配置,示例配置如下:
# 拒绝所有非本地连接,仅允许本地scram认证 local all all scram-sha-256 host all all 127.0.0.1/32 scram-sha-256 host all all ::1/128 scram-sha-256 # 如果必须允许远程连接,限定来源IP并使用scram host all all 192.168.10.0/24 scram-sha-256
除了认证方式,还应当限制数据库监听的地址。postgresql.conf中的listen_addresses参数默认值可能是localhost或者包含所有地址,生产环境建议仅绑定内网网卡地址,例如listen_addresses = '192.168.10.20'。同时关闭不必要的网络端口,使用防火墙或安全组进一步限制可访问数据库的IP范围。对于高安全要求的场景,可以结合基于证书的客户端认证(cert认证),要求客户端提供由受信任CA签发的证书,这样即使密码泄露也无法直接登录。
角色管理同样需要遵循最小权限原则。避免所有应用使用超级用户连接,应当为每个业务模块创建独立的普通角色,并只授予必要的表权限。使用GRANT SELECT, INSERT, UPDATE ON table_name TO app_role;而非直接将角色加入超级用户组。此外可以通过ALTER ROLE app_role NOSUPERUSER NOCREATEDB NOCREATEROLE;显式禁止角色提升权限。如果应用需要执行DDL操作,也建议通过单独的管理角色或受控的迁移脚本来完成,而不是让应用账号持有DDL权限。
数据加密与网络传输安全
PostgreSQL支持SSL/TLS加密客户端与服务端之间的通信。默认情况下SSL可能是关闭的,即使开启了也可能只加密传输而不校验证书,这容易遭受中间人攻击。要启用SSL,需要在postgresql.conf中设置ssl = on,并配置服务器证书和私钥路径,例如ssl_cert_file = 'server.crt'和ssl_key_file = 'server.key'。建议使用权威CA签发的证书,或者内部PKI签发的证书,避免使用自签名证书而让客户端忽略验证。
客户端连接字符串可以指定sslmode=require或更严格的sslmode=verify-full。verify-full模式会验证服务器证书的CN或SAN与连接主机名一致,能有效防止中间人攻击。如果使用JDBC驱动,连接参数为ssl=true&sslmode=verify-full&sslrootcert=/path/to/ca.crt。对于内部服务之间的连接,也可以使用客户端证书进行双向认证,配置pg_hba.conf中的hostssl条目配合cert认证方式。
除了传输加密,还需要考虑存储层的数据加密。PostgreSQL本身不提供完整的透明数据加密(TDE),但可以使用pgcrypto扩展对敏感列进行应用层加密。例如使用pgp_sym_encrypt和pgp_sym_decrypt函数加密信用卡号、身份证号等字段。示例代码如下:
-- 创建扩展
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- 插入加密数据,密钥仅存在于应用层
INSERT INTO users (name, card_number_encrypted)
VALUES ('张三', pgp_sym_encrypt('6222021234567890', 'my_secret_key'));
-- 查询时解密
SELECT name, pgp_sym_decrypt(card_number_encrypted, 'my_secret_key') AS card_number
FROM users;
需要注意的是,应用层加密会导致无法对加密列建立普通索引进行等值查询,如果必须按加密列检索,可以使用盲索引方案(例如存储哈希值作为额外列)。另外密钥管理需要借助外部KMS或密钥管理服务,不要把密钥硬编码在应用代码或配置文件中。对于文件系统层面的加密,可以使用LUKS或云厂商的磁盘加密功能,这能防止物理磁盘被盗导致的数据泄露,但无法防御数据库进程被入侵后的读取。
审计日志与异常行为监控
没有审计日志的数据库在发生安全事件后很难追溯攻击路径和操作内容。PostgreSQL内置的日志功能可以记录连接、断开、错误和慢查询,但默认的日志参数过于简单。建议在postgresql.conf中开启详细日志:设置logging_collector = on、log_directory = 'pg_log'、log_connections = on、log_disconnections = on、log_statement = 'ddl'。其中log_statement = 'ddl'至少记录所有DDL语句,便于发现未授权的表结构变更。对于DML语句,可以设置为log_statement = 'mod'记录INSERT、UPDATE、DELETE,但这会产生大量日志,需要根据磁盘和性能权衡。
如果需要对特定表或特定操作进行细粒度审计,推荐使用pgaudit扩展。pgaudit能够记录审计级别的详细事件,包括对象访问、权限变更、角色管理等。安装后需要在shared_preload_libraries中加载pgaudit,并配置pgaudit.log参数。示例配置:
-- postgresql.conf 中添加 shared_preload_libraries = 'pgaudit' pgaudit.log = 'write, ddl, role' pgaudit.log_catalog = off
启用pgaudit后,所有对表的写操作、DDL语句和角色管理命令都会被记录到日志中,包含用户名、客户端地址、执行语句和事务ID等信息。可以将日志收集到集中式日志系统(如ELK、Loki)中,并配置告警规则,例如当出现连续登录失败、超级用户执行敏感命令或者从异常IP发起连接时触发通知。此外还可以结合pg_stat_activity视图实时监控活跃会话,定期检查长时间运行的事务和异常客户端。
参数加固与备份恢复安全
PostgreSQL的许多配置参数也会影响安全性。例如password_encryption应设置为scram-sha-256,避免使用md5;ssl_prefer_server_ciphers应保持默认开启,防止客户端指定弱加密套件;log_min_error_statement建议设置为error,确保错误语句被记录;statement_timeout可以设置合理值防止恶意长查询耗尽资源。对于超级用户权限,可以通过ALTER SYSTEM SET allow_system_table_mods = off;防止系统表被直接修改。这些参数需要在postgresql.conf中统一调整,修改后执行SELECT pg_reload_conf();使其生效。
备份数据的安全同样不容忽视。使用pg_dump或pg_basebackup生成的备份文件包含完整数据,如果备份文件存储在不安全的位置,等同于数据泄露。建议对备份文件进行加密后再传输或存储,例如使用gpg对称加密或存储到启用服务器端加密的对象存储中。同时定期验证备份的可恢复性,确保在安全事件发生后能够快速恢复数据。对于时间点恢复(PITR),需要安全地管理WAL归档,归档目录的权限应严格限制,避免WAL文件被篡改。
最后要建立定期漏洞扫描和版本升级机制。关注PostgreSQL官方发布的安全公告,及时应用小版本更新。使用SELECT version();确认当前版本,如果存在已知CVE漏洞,必须尽快升级。对于无法立即升级的场景,可以临时限制相关功能或使用防火墙阻断利用路径。安全增强是一个持续的过程,需要结合组织内部的安全基线进行定期审计和配置核查。
PostgreSQL安全数据库加固访问控制修改时间:2026-10-02 11:07:05