14、PostgreSQL数据库加固

PostgreSQL 等保三级安全加固:password_encryption=scram-sha-256(10+)与 pg_hba.conf 认证方法同步、passwordcheck 扩展与 shared_preload_libraries、VALID UNTIL 口令有效期、SYSTEM/SSEO/SYSSAO 式的三权分立角色划分(用三个独立 ROLE 分持 superuser 替代权限)、多余角色治理与 rolcanlogin 核查、对象权限最小化与 REVOKE PUBLIC、pg_hba.conf 消除 trust 行并按 hostssl+scram-sha-256 收敛、listen_addresses 与 port 限制、ssl=on 与 ssl_min_protocol_version=TLSv1.2(12+)、pgAudit 扩展安装与 pgaudit.log 审计类配置、log_statement/log_connections/log_disconnections/log_line_prefix 日志要素、logging_collector 与日志轮转留存、idle_session_timeout(14+)与 idle_in_transaction_session_timeout(9.6+)、pg_dump/pg_basebackup 配合 WAL 归档备份与恢复演练、无内置登录失败锁定时的 fail2ban 替代。

定位:PostgreSQL 9.6~17 等保三级安全加固手册:按身份鉴别、访问控制、网络访问控制、传输加密、安全审计、日志管理、数据备份恢复分节,每节给出 postgresql.conf/pg_hba.conf 配置与 psql 验证命令,并说明旧版文章常见无效语法。

适用版本:PostgreSQL 9.617(示例按 1216 验证;国产 PG 系如 KingbaseES 可参考机制,命令前缀与视图名以对应手册为准)。版本差异:idle_session_timeout 需 14+(9.6~13 仅有 idle_in_transaction_session_timeout);password_encryption 默认 scram-sha-256 自 14 起(13 及以下为 md5,需显式设置);pg_monitor 预置角色与 pg_hba_file_rules 视图需 10+;ALTER SYSTEM 需 9.4+。 配套测评:PostgreSQL 测评命令。

使用说明:

  • 本文为加固操作手册:所有命令都会修改配置,可能中断服务、断开当前会话或需要重启。实施前必须完成变更审批、确认业务窗口、备份原配置(设备 save 与 copy running-config/backup startup-configuration,主机备份 /etc、注册表与关键业务数据),并准备可执行的回滚预案。
  • 先在测试环境或单台设备灰度验证,确认无业务影响后再批量推广;每完成一项立即用文中「验证」命令核验生效——配置已下发不等于策略已生效(如 H3C 未 password-control enable、Linux 未对存量账户 chage、Windows 未 gpupdate /force)。
  • 示例中的地址、账户名、口令、路径均为演示值(如 PleaseChange@123、192.168.10.20、admin123),现场须替换为符合本单位口令策略与网络规划的真实值,严禁直接沿用文中示例口令;对外发布或归档时须对个人信息与内网管理地址脱敏。
  • 命令不存在、视图名或参数与本文不一致时,先用 display version / show version / winver 确认版本与部署形态,再查阅对应版本官方文档换用等效命令;版本差异不得直接作为「无法整改」的结论,须给出替代措施并评估其实际效果。
  • 涉及账户、锁定、超时、防火墙与端口收敛的变更存在锁死自身风险:务必保留一条已验证的恢复通道(Console 口、带外管理口、堡垒机会话或另一管理员账户)后再实施。
  • 加固完成后按「16、安全评估加固记录表3.0」逐项留痕(整改前后回显、操作人、时间、验证结论、回退情况),并纳入复测;测评判定口径以 GB/T 28448-2019 与《高风险判定指引》为准,本文的「加固要点」不构成最终测评结论。

不适用标识说明:

  • 使用 【不适用】 明确标记现场可判定为不适用的控制点,并写明判定依据与承载该能力的上位组件。
  • 依据 GB/T 28448-2019「按测评对象实际承载功能与数据处理范围判定」原则:控制能力由统一认证平台、堡垒机、日志审计系统、终端管理系统、虚拟化平台或云托管平台承载时,应注明测评单元边界后判定不适用或转由上位组件核查,不得机械按缺失判不符合。
  • 产品版本确实不提供该能力(如老旧设备无 SNMPv3、无可信根、社区版无审计模块、已停止官方支持的操作系统)时,须核查替代措施并按替代措施的实际效果定档,不得直接判不适用;已停止支持的版本应同时提出升级或补偿控制建议。

一、身份鉴别

对应控制点:GB/T 22239-2019 8.1.4.1 身份鉴别 a)~d)(数据库管理系统自身账户标识与鉴别)

加固要点:数据库账户须唯一实名、禁止共用与空口令:删除或锁定安装时产生的多余账户与测试对象(MySQL 的匿名账户与 test 库、PostgreSQL 与操作系统同名的默认账户、MongoDB 创建首个用户前的 localhost exception、达梦与金仓的默认示例账户),管理账户按「系统管理员 / 安全保密管理员 / 安全审计员」三权分立建账(DM 的 SYSDBA/SYSSSO/SYSAUDITOR、KingbaseES 的 SYSTEM/SSEO/SYSSAO、PostgreSQL 用三个独立 ROLE 分持权限、MySQL 用独立管理账户并按权限分离),应用连接账户与 DBA 账户严格分离且只授予业务库的对象权限。鉴别信息复杂度与有效期按 8.1.4.1 a) 配置并逐账户下发生效;三级系统须核查最高权限账户是否同受约束。

验证方法:账户清单与权限矩阵(MySQL SELECT user,host,account_locked,password_expired,plugin FROM mysql.user;、PostgreSQL \du+ 与 SELECT rolname,rolsuper,rolcreatedb,rolcreaterole,rolcanlogin,rolvaliduntil FROM pg_roles;、MongoDB db.getUsers() 与 db.getUser("<u>")、达梦 SELECT USERNAME,ACCOUNT_STATUS,LOCK_DATE FROM DBA_USERS;、金仓 SYS_USERS 视图或 \du)+ 口令策略参数回显 + 三权分立的分权实测(用安全审计员账户执行 DBA 操作应被拒)+ 一次真实登录记录。

1.1 口令加密存储(scram-sha-256)

对应控制点:GB/T 22239-2019 8.1.4.1 身份鉴别 a)、8.1.4.8 数据保密性 a)(配置与口令文件中不得出现明文鉴别信息)

加固要点:鉴别信息必须以不可逆散列存储,配置、脚本与备份中不得出现明文口令:MySQL 8.0 默认 caching_sha2_password(5.7 的 mysql_native_password 为 SHA1 双次散列、强度较弱,升级到 8.0 后应逐账户转换);PostgreSQL 设 password_encryption=scram-sha-256(10+,md5 为旧方式,9.x 仅支持 md5)并在 pg_hba.conf 使用 scram-sha-256 认证方法,改动后须重设口令才会以新方式存储;MongoDB 设 authenticationMechanisms: SCRAM-SHA-256 并禁用已废弃的 MONGODB-CR;达梦与金仓按对应版本手册确认口令散列算法。连接串、.my.cnf、.pgpass、应用配置与 CI 变量中的口令须加密存放或使用凭据管理系统,禁止提交到代码仓库。

验证方法:SELECT user,host,plugin FROM mysql.user;(应无 mysql_native_password 遗留或已说明原因)、SHOW password_encryption; 与 SELECT rolname,left(rolpassword,14) FROM pg_authid;(散列前缀应为 SCRAM-SHA-)、db.adminCommand({getParameter:1,authenticationMechanisms:1}) 与 db.getSiblingDB("admin").system.users.findOne() 的 mechanisms 字段、~/.pgpass 与 .my.cnf 权限(0600)、代码仓库检索明文口令的结果。

核查方法

show password_encryption;
select rolname, substring(rolpassword,1,20) as hash_head from pg_authid where rolcanlogin;
示例输出(节选)
postgres=# show password_encryption;
 password_encryption
---------------------
 scram-sha-256

postgres=# select rolname, substring(rolpassword,1,20) as hash_head from pg_authid where rolcanlogin;
 rolname  |      hash_head
----------+-----------------------
 appuser  | SCRAM-SHA-256$4096:...
 postgres | SCRAM-SHA-256$4096:...

密文以 SCRAM-SHA-256$ 开头为符合;md5 开头为弱机制。

加固操作

-- postgresql.conf:password_encryption = scram-sha-256(PG14+ 默认)
ALTER SYSTEM SET password_encryption = 'scram-sha-256';
select pg_reload_conf();

-- 重设口令使其以 scram 存储
ALTER ROLE appuser PASSWORD 'YourStrong@Passw0rd';

1.2 口令复杂度(passwordcheck 扩展)

对应控制点:GB/T 22239-2019 8.1.4.1 身份鉴别 a)(身份鉴别信息具有复杂度要求并定期更换)

加固要点:按「复杂度 + 长度 + 老化 + 历史」四要素配置并对全部账户生效:最小长度不低于 8 位(管理账户建议 12~16 位)、至少包含大写字母/小写字母/数字/特殊字符中三类、老化不超过 90 天、历史防重复不少于 5 次。落地方式因产品而异——MySQL 8.0 用 validate_password 组件(5.7 为插件,参数名 validate_password_policy/validate_password_length 与 8.0 的 validate_password.policy/.length 写法不同);PostgreSQL 用 contrib 的 passwordcheck 扩展(须写入 shared_preload_libraries 后重启,能力较弱,长度与字符类组合须辅以应用侧或制度约束);MongoDB 无内置口令复杂度校验,须在账户创建流程与配置管理中约束并说明;达梦用 PWD_POLICY/PASSWORD_POLICY 位掩码与 PWD_MIN_LEN;金仓用 PROFILE 机制。无论采用哪种方式,都须核查最高权限账户是否同受约束,并对存量账户逐个下发有效期。

验证方法:口令策略参数回显(SHOW VARIABLES LIKE 'validate_password%';、SHOW shared_preload_libraries; 与 CREATE EXTENSION passwordcheck 结果、达梦 SELECT * FROM V$PARAMETER WHERE NAME LIKE 'PWD%';、金仓 PROFILE 定义)+ 存量账户有效期抽查(MySQL SELECT user,host,password_expired,password_lifetime FROM mysql.user;、PostgreSQL rolvaliduntil、达梦 DBA_USERS.EXPIRY_DATE)+ 一次弱口令设置被拒的实测记录。

PG 原生不做复杂度校验,启用内置 passwordcheck 扩展(校验最小长度 8、禁止与用户名相同):

# postgresql.conf
shared_preload_libraries = 'passwordcheck'
# Debian 系:apt install postgresql-contrib;RHEL 系:yum install postgresql-contrib
systemctl restart postgresql

更细的复杂度策略可使用企业版/第三方扩展(如 citus 的 passwordcheck.cracklib),或由运维基线保证。判定标准:至少具备 passwordcheck 级别的口令强度校验。

1.3 口令有效期(VALID UNTIL)

对应控制点:GB/T 22239-2019 8.1.4.1 身份鉴别 a)(身份鉴别信息具有复杂度要求并定期更换)

核查方法

select rolname, rolvaliduntil from pg_roles where rolcanlogin;
示例输出(节选)
 rolname  |       rolvaliduntil
----------+------------------------
 appuser  | 2027-01-01 00:00:00+08
 postgres | infinity

加固操作(正确语法,ROLVALIDUNTIL 到期后该账户无法登录):

ALTER ROLE appuser VALID UNTIL '2027-01-01 00:00:00+08';
ALTER ROLE appuser VALID UNTIL now() + interval '90 days';

1.4 登录失败处理(如实说明 + fail2ban 落地)

对应控制点:GB/T 22239-2019 8.1.4.1 身份鉴别 b)(提供登录失败处理功能,限制非法登录次数)

加固要点:提供并启用登录失败处理功能:MySQL 8.0 用 connection_control 插件(connection_control_failed_connections_threshold 建议 3~5,min_connection_delay/max_connection_delay 递增延时);PostgreSQL 无内置失败锁定,须以 fail2ban、pgbouncer 或数据库审计系统联动实现,并如实说明替代措施与其实际效果;MongoDB 无内置失败锁定,以 net.bindIp 配合防火墙限制来源、审计与告警联动实现;达梦用 FAILED_LOGIN_ATTEMPS(注意官方关键字拼写少一个 T)与 PASSWORD_LOCK_TIME;金仓用 PROFILE 的失败次数与锁定时长。策略须覆盖最高权限账户,并保留一条已验证的恢复通道(本地 socket 登录、单用户维护模式或另一管理员账户),避免锁定即失联。

验证方法:失败处理参数回显(SHOW VARIABLES LIKE 'connection_control%';、\dx 确认插件已安装、达梦与金仓的 LIMIT 与 PROFILE 定义)+ 一次真实失败登录实测:连续输错至阈值后确认账户被拒或延时递增,并记录解锁方式与解锁后登录成功;采用替代措施时须附 fail2ban 规则与触发日志(fail2ban-client status <jail>)。

PG 原生不支持登录失败次数锁定(Oracle 的 FAILED_LOGIN_ATTEMPTS 概念不适用)。可落地方式:

  1. 运维层 fail2ban 监控 PG 日志中的认证失败并封禁来源 IP:
# /etc/fail2ban/filter.d/postgresql.conf
[Definition]
failregex = ^.*FATAL:.*password authentication failed for user.*client address <HOST>.*$
            ^.*FATAL:.*no pg_hba.conf entry.*<HOST>.*$

# /etc/fail2ban/jail.d/postgresql.local
[postgresql]
enabled  = true
port     = 5432
filter   = postgresql
logpath  = /var/log/postgresql/postgresql-16-main.log
maxretry = 5
findtime = 600
bantime  = 600
systemctl restart fail2ban && fail2ban-client status postgresql
示例输出(节选)
Status for the jail: postgresql
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     7
`- Actions
   |- Currently banned: 1
   |- Total banned:     1
   `- Banned IP list:   192.168.10.99
  1. 应用侧连接池/网关(如 pgbouncer、数据库防火墙)配置失败次数限制。

1.5 会话超时

对应控制点:GB/T 22239-2019 8.1.4.1 身份鉴别 b)(配置并启用结束会话、登录连接超时自动退出)

加固要点:所有数据库会话统一配置空闲超时并限制单会话生命周期:MySQL 设 wait_timeout/interactive_timeout(建议 300~600 秒,不得为默认 28800 秒不收紧)并按账户设 MAX_USER_CONNECTIONS;PostgreSQL 用 idle_session_timeout(14+)与 idle_in_transaction_session_timeout(9.6+,防长事务占锁)配合 statement_timeout,13 及更早版本无 idle_session_timeout 时以 pgbouncer 的 server_idle_timeout/client_idle_timeout 或应用侧连接池回收实现并说明;MongoDB 无服务端会话空闲超时,以 net.maxIncomingConnections 与应用侧连接池控制;图形客户端与 Web 管理台自身的会话超时同样须配置。超时值不得为 0。

验证方法:参数回显(SHOW VARIABLES LIKE '%timeout%';、SHOW idle_session_timeout; SHOW idle_in_transaction_session_timeout;、db.adminCommand({getParameter:1,maxIncomingConnections:1}))+ 一次实测:建立空闲连接静置至阈值后确认被服务端断开(客户端报连接失效)+ 连接池或代理配置截图。

核查方法

show idle_in_transaction_session_timeout;
show idle_session_timeout;      -- PG14+
show statement_timeout;

加固操作(按角色粒度设置,空闲事务/空闲会话 30 分钟):

ALTER ROLE appuser SET idle_in_transaction_session_timeout = '30min';
ALTER ROLE appuser SET idle_session_timeout = '30min';   -- PG14+
select rolname, rolconfig from pg_roles where rolname='appuser';

二、访问控制

对应控制点:GB/T 22239-2019 8.1.4.2 访问控制 a)~g)(数据库账户、角色与对象权限;三权分立对应 d) 重命名与 e) 敏感标记、f) 授权主体最小化)

加固要点:按最小权限授予:账户只授予其业务所需的库/模式/对象权限与操作类型,禁止对业务账户直接授予 SUPER/SYSDBA/DBA/root 等最高权限;权限变更须经审批并留痕,回收后核验生效。启用数据库自身的访问控制机制限制登录来源(PostgreSQL pg_hba.conf、KingbaseES sys_hba.conf、MySQL 账户的 host 部分与 require_secure_transport、MongoDB net.bindIp 配合主机防火墙、达梦与金仓的 IP 白名单或操作系统层限制),并禁止 trust、any、无口令等无鉴别访问方式。敏感数据(个人身份信息、鉴别信息)须打敏感标记或单独建库建表并限制可访问账户。

验证方法:权限授予清单(MySQL SHOW GRANTS FOR 'u'@'h';、PostgreSQL \dp 与 information_schema.table_privileges、MongoDB db.getUser() 的 roles 字段、达梦与金仓 DBA_ROLE_PRIVS/DBA_TAB_PRIVS)与业务需要清单逐项比对;pg_hba.conf/sys_hba.conf 全文(应无 trust 行);从非授权网段或非授权账户发起连接被拒的实测记录;敏感标记或数据分级分类文档。

2.1 三权分立账户

对应控制点:GB/T 22239-2019 8.1.4.2 访问控制 a)~g)(数据库账户、角色与对象权限;三权分立对应 d) 重命名与 e) 敏感标记、f) 授权主体最小化)

核查方法

select rolname, rolsuper, rolcreaterole, rolcreatedb, rolcanlogin from pg_roles where rolcanlogin;
示例输出(节选)
 rolname   | rolsuper | rolcreaterole | rolcreatedb | rolcanlogin
-----------+----------+---------------+-------------+-------------
 postgres  | t        | t             | t           | t
 sysadmin  | f        | f             | t           | t
 secadmin  | f        | t             | f           | t
 audadmin  | f        | f             | f           | t
 appuser   | f        | f             | f           | t

加固操作:建立系统管理员(业务运维)、安全管理员(角色/权限)、审计管理员(日志查询)三类角色,超级用户仅限本地维护:

CREATE ROLE sysadmin LOGIN PASSWORD 'YourStrong@Passw0rd' CREATEDB;
CREATE ROLE secadmin LOGIN PASSWORD 'YourStrong@Passw0rd' CREATEROLE;
CREATE ROLE audadmin LOGIN PASSWORD 'YourStrong@Passw0rd';   -- 授予监控/读日志角色
GRANT pg_monitor TO audadmin;
  • 预置角色参考:pg_monitor(审计/监控查询)、pg_read_all_settings、pg_read_all_stats;
  • postgres 超级用户重命名风险大(部分扩展假定其存在),不建议改名,改为限制其网络可达性(见三.2)并强化口令。

2.2 多余账户治理

对应控制点:GB/T 22239-2019 8.1.4.2 访问控制 a)~g)(数据库账户、角色与对象权限;三权分立对应 d) 重命名与 e) 敏感标记、f) 授权主体最小化)

select rolname from pg_roles where rolcanlogin;   -- 全部可登录账户
DROP ROLE 废弃用户;                                -- 需先转移/回收其对象权限
REASSIGN OWNED BY 废弃用户 TO sysadmin;
DROP OWNED BY 废弃用户;
DROP ROLE 废弃用户;

2.3 对象权限最小化

对应控制点:GB/T 22239-2019 8.1.4.2 访问控制 a)d)f)(数据目录与关键文件权限、运行账户、特权存储过程与外部命令执行能力)

加固要点:数据库运行账户与文件权限最小化:实例不得以 root 或 Administrator 运行(PostgreSQL 强制非 root 启动、MySQL 使用 mysql 系统账户、MongoDB 使用 mongod 账户、Windows 侧使用低权限专用服务账户);数据目录、配置文件、备份目录与日志目录权限收敛到运行账户(Linux 0700/0600,Windows 移除 Users 的完全控制),防止其他本地账户直接读写数据文件绕过数据库鉴权;数据库内特权能力(外部命令执行、文件读写、链接服务器、SUPER、COPY ... PROGRAM、达梦与金仓的系统包)按账户逐一收敛,禁止业务账户持有。

验证方法:ps -ef | grep -E "mysqld|postgres|mongod|dmserver" 与 Get-CimInstance Win32_Service 确认运行账户、ls -ld 或 stat 输出数据目录与关键文件权限、Windows 侧 icacls 输出、数据库内特权账户清单与特权能力授予情况(SHOW GRANTS、pg_roles.rolsuper、MongoDB 持有 root/clusterAdmin 角色的账户)。

REVOKE ALL ON DATABASE appdb FROM PUBLIC;      -- 收回 PUBLIC 默认连接/建 Schema 权限
GRANT CONNECT ON DATABASE appdb TO appuser;
GRANT USAGE ON SCHEMA app TO appuser;
GRANT SELECT, INSERT, UPDATE ON app.t1 TO appuser;   -- 按需授权,不做 ALL

核查越权:\dn+、\dp app.t1、select * from information_schema.role_table_grants where grantee='appuser';

三、网络访问控制(pg_hba.conf)

对应控制点:GB/T 22239-2019 8.1.4.2 访问控制 a)~g)(数据库账户、角色与对象权限;三权分立对应 d) 重命名与 e) 敏感标记、f) 授权主体最小化)

3.1 编辑 pg_hba.conf

pg_hba.conf 是文件,直接编辑(路径:show hba_file;)。每行五列:TYPE / DATABASE / USER / ADDRESS / METHOD:

# 类型      数据库     用户        地址                  认证方式
local       all        postgres                          peer          # 本地 postgres 走系统账户对等认证
hostssl     appdb      appuser     192.168.10.0/24       scram-sha-256 # 业务网段:仅 TLS + scram
host        appdb      appuser     192.168.10.0/24       reject        # 未用 TLS 的同网段连接拒绝
host        all        all         0.0.0.0/0             reject        # 显式兜底拒绝(书写明确,便于审计)
host        all        all         ::0/0                 reject

3.2 生效与核查

pg_ctl reload -D $PGDATA        # 或:
select pg_reload_conf();
-- 核查解析结果与错误行(这是检查 pg_hba 的正确途径,不存在 UPDATE pg_hba_file 语法)
select line_number, type, database, user_name, address, auth_method, error
from pg_hba_file_rules where error is not null;
select * from pg_hba_file_rules order by line_number;
示例输出(节选)
 line_number | type    | database | user_name | address         | auth_method | error
-------------+---------+----------+-----------+-----------------+-------------+-------
          90 | local   | all      | postgres  |                 | peer        |
          91 | hostssl | appdb    | appuser   | 192.168.10.0/24 | scram-sha-256|
          92 | host    | all      | all       | 0.0.0.0/0       | reject      |

3.3 监听地址与端口

对应控制点:GB/T 22239-2019 8.1.4.4 入侵防范 a)~f)(最小安装与组件收敛、监听与端口限制、危险能力关闭、漏洞与补丁管理)

加固要点:按最小化原则收敛数据库暴露面:仅安装业务所需组件(去掉示例库、示例脚本、可选的 Web 管理台与客户端工具),关闭不需要的服务与端口;监听地址限定到业务网段(禁止 0.0.0.0 或 bindIp: 0.0.0.0 直连公网),端口经主机防火墙与边界策略双重限制到应用服务器与运维堡垒机;关闭高危能力(MySQL local_infile=OFF 并设置 secure_file_priv、启用 skip_symbolic_links;PostgreSQL 限制 COPY ... PROGRAM、lo_import/lo_export、file_fdw;MongoDB security.javascriptEnabled: false 并确认未启用旧版 HTTP 接口);建立版本与漏洞台账,跟踪官方安全公告并按变更窗口修补,已停止官方支持的版本须提出升级或补偿控制建议。

验证方法:已安装组件与版本清单、监听地址与端口回显(ss -tlnp 或 netstat -ano、MySQL SHOW VARIABLES LIKE 'bind_address';、PostgreSQL SHOW listen_addresses; SHOW port;、MongoDB net.bindIp 配置)、主机防火墙与边界策略截图、高危参数当前值回显、漏洞台账与补丁记录、官方安全公告订阅证据(MySQL Release Notes、PostgreSQL 官方邮件列表与 Release Notes、MongoDB Release Notes、达梦与金仓官网公告)。

核查方法

show listen_addresses;
show port;

加固操作

ALTER SYSTEM SET listen_addresses = '192.168.10.10';   -- 只监听业务网卡,禁 * 泛监听
select pg_reload_conf();

修改端口(如必须)需重启实例并同步防火墙:ALTER SYSTEM SET port = 5433; 后重启。改端口仅为纵深防御,不作为安全判定项。

四、传输加密(SSL)

对应控制点:GB/T 22239-2019 8.1.4.7 数据完整性 a)、8.1.4.8 数据保密性 a)、8.1.2.2 通信传输 a)b)(客户端与服务端间 SSL/TLS)

加固要点:客户端与数据库服务端之间的通信须加密并强制使用:MySQL require_secure_transport=ON 或账户级 REQUIRE SSL/REQUIRE X509、PostgreSQL ssl=on 且 pg_hba.conf 用 hostssl 替代 host 并设 ssl_min_protocol_version=TLSv1.2(12+)、MongoDB net.tls.mode: requireTLS、达梦与金仓按对应版本手册启用通信加密;证书由内部 CA 或可信 CA 签发且在有效期内,禁用 SSLv3/TLS1.0/TLS1.1 与弱套件;集群内部节点间通信(副本集、复制链路)同样须加密并启用内部认证(MongoDB keyFile 或 x.509、MySQL 复制通道 MASTER_SSL=1/SOURCE_SSL=1)。仅「支持加密」而未强制不构成符合。

验证方法:服务端 SSL 参数与证书路径回显、证书有效期与签发者(openssl x509 -in <cert> -noout -dates -issuer -subject)、pg_hba.conf 中的 hostssl 行、客户端连接实测:以 --ssl-mode=DISABLED 或 sslmode=disable 连接应被拒,以加密方式连接后用 \conninfo、SHOW STATUS LIKE 'Ssl_cipher';、db.serverStatus().security 确认实际协商的协议与套件版本。

核查方法

show ssl;
show ssl_min_protocol_version;
select * from pg_stat_ssl where pid = pg_backend_pid();   # 当前连接的加密状态
示例输出(节选)
postgres=# show ssl;
 ssl
-----
 on

postgres=# select ssl, version, cipher, bits from pg_stat_ssl where pid = pg_backend_pid();
 ssl | version |           cipher            | bits
-----+---------+-----------------------------+------
 t   | TLSv1.3 | TLS_AES_256_GCM_SHA384      |  256

加固操作(postgresql.conf;证书由单位 CA 签发):

ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'
ssl_ca_file = 'ca.crt'
ssl_min_protocol_version = 'TLSv1.2'
chmod 600 server.key && chown postgres:postgres server.key
systemctl restart postgresql

客户端验证:psql "host=192.168.10.10 dbname=appdb user=appuser sslmode=require",连接后 \conninfo 显示 SSL connection。

五、安全审计(pgAudit)

对应控制点:GB/T 22239-2019 8.1.4.3 安全审计 a)~d)(数据库审计策略、审计记录内容、留存与保护)

加固要点:启用数据库审计并覆盖:用户登录注销、账户与权限变更(DDL/DCL)、对敏感数据与关键表的访问、审计策略自身的修改;审计记录须包含事件日期时间、用户、事件类型、是否成功、客户端地址等要素;审计功能由独立的安全审计员账户管理,系统管理员不得删除或篡改审计记录;审计日志留存不少于 6 个月并定期备份,容量写满时按策略告警而非静默覆盖。社区版无原生审计能力时(PostgreSQL 需 pgAudit、MongoDB 社区版无 auditLog、MySQL 社区版无 audit_log),须部署数据库审计系统、堡垒机或操作系统层审计作为替代,并在报告中写明测评单元边界与替代措施的实际效果。

验证方法:审计开关与审计策略配置回显(PostgreSQL SHOW shared_preload_libraries; 含 pgaudit + pgaudit.log 参数 + \dx 确认扩展已创建;MySQL SHOW VARIABLES LIKE '%audit%'; 或企业版 audit_log_policy;MongoDB 企业版 auditLog 配置段;达梦与金仓的审计参数与审计项/审计对象配置结果)+ 一段真实审计记录样例(含时间、用户、来源 IP、操作对象、结果)+ 审计记录留存起始时间与备份记录 + 用系统管理员账户尝试删除审计记录被拒的实测。

内置 csvlog 可记录连接/断开与语句,精细审计推荐 pgAudit 扩展:

# postgresql.conf
shared_preload_libraries = 'passwordcheck,pgaudit'
pgaudit.log = 'ddl, write, role'     # 审计 DDL、DML 写操作、角色变更
pgaudit.log_relation = on            # 逐语句记录对象
pgaudit.log_catalog = off
# 安装扩展包(contrib/epel 源)
yum install pgaudit      # 或编译安装
systemctl restart postgresql
-- 预加载后仍需创建扩展(部分发行版打包为 pgaudit)
CREATE EXTENSION pgaudit;
select * from pg_extension where extname='pgaudit';
-- 日志核查:csvlog 中可见 AUDIT 行
  • 判定标准:覆盖账户/权限变更与数据写操作,日志留存 ≥6 个月。仅 csvlog(连接断开级)一般判部分符合。

六、日志管理

对应控制点:GB/T 22239-2019 8.1.4.3 安全审计 a)~d)(数据库审计策略、审计记录内容、留存与保护)

核查方法

show logging_collector; show log_destination; show log_connections; show log_statement;

加固操作(postgresql.conf):

logging_collector = on
log_destination = 'csvlog'
log_directory = 'log'
log_filename = 'postgresql-%Y-%m-%d.log'      # 按天滚动
log_file_mode = 0600
log_connections = on
log_disconnections = on
log_statement = 'mod'                         # 记录写类语句(all 开销大,评估后选用)
log_min_duration_statement = 1000             # 慢查询 1 秒
log_line_prefix = '%m [%p] user=%u,db=%d,client=%h '
log_truncate_on_rotation = on
select pg_reload_conf();
  • 留存 ≥6 个月:按天滚动 + 定期归档至日志服务器,或配 OS logrotate;
  • 时间同步:主机配置 NTP(timedatectl、chronyc sources 核查,配置见 11 号)。

七、数据备份恢复

对应控制点:GB/T 22239-2019 8.1.4.9 数据备份恢复 a)~c)(本地备份、异地实时备份与热冗余)

加固要点:建立并实际执行备份策略:本地定时全量 + 增量或日志备份(MySQL mysqldump/mysqlpump 配合 binlog、PostgreSQL pg_dump/pg_basebackup 配合 WAL 归档、MongoDB mongodump 配合 oplog 或文件系统快照、达梦与金仓使用自带备份工具),备份文件与主数据分机存放并异地留存(三级要求异地实时备份或热冗余),备份数据同样加密并限制访问权限;每半年至少一次恢复演练并留存演练记录,RTO/RPO 与业务要求匹配。仅有备份脚本而无恢复验证不判符合。

验证方法:备份策略与计划任务配置、最近若干次备份任务的执行日志与产物清单(大小、时间、存放位置)、异地备份或热冗余证据(异地备份目录、流复制或副本集状态:SHOW REPLICA STATUS\G、SELECT * FROM pg_stat_replication;、rs.status())、恢复演练记录(时间、参与人、恢复耗时、数据一致性校验结果)、备份文件权限与加密方式。

核查方法:crontab -l、备份文件时效、恢复演练记录。

加固操作

# 逻辑备份(库级)
pg_dump -U postgres -h localhost -p 5432 -Fc appdb > /backup/appdb_$(date +%F).dump
chmod 600 /backup/appdb_*.dump

# 实例级全量(含物理一致性)
pg_dumpall -U postgres -h localhost -p 5432 --file /backup/globals_$(date +%F).sql

# 物理基础备份(配合 WAL 归档可做 PITR)
pg_basebackup -U replicator -h 192.168.10.10 -D /backup/base_$(date +%F) -X stream -P

WAL 归档(postgresql.conf):

archive_mode = on
archive_command = 'test ! -f /archive/%f && cp %f /archive/%f'
  • 恢复演练:pg_restore -U postgres -d appdb_test /backup/appdb_xxx.dump 定期验证;
  • 异地备份:备份目录同步至异地(rsync over ssh);三级系统应有异地备份与实例冗余(流复制 pg_stat_replication 或 HA)。

八、常见误区澄清

误区(无效写法)正确做法
UPDATE pg_hba_file SET ...pg_hba.conf 是文件:直接编辑 + select pg_reload_conf();,用 pg_hba_file_rules 视图核查
ALTER USER u FAILED_LOGIN_ATTEMPTS 5 PASSWORD_LOCK_TIME '10min'Oracle 方言,PG 无此语法;用 fail2ban 监控日志实现失败锁定(见 1.4)
ALTER USER u VALID UNTIL 'now' + INTERVAL '90 days'字符串拼接不成立;写 VALID UNTIL now() + interval '90 days'
ALTER SYSTEM SET port = 5432 立即生效端口等连接参数需重启实例
GRANT CONNECT TO u 收回远程权限网络可达性由 pg_hba.conf 控制;CONNECTION LIMIT 0 仅禁新连接,不替代访问控制
OS 层 systemctl/firewall 命令属操作系统加固,见 04/11 号文章

测评项对照表

控制点对应章节
身份鉴别:口令加密存储、复杂度、有效期一
身份鉴别:登录失败处理一.4
身份鉴别:会话超时一.5
访问控制:账户权限最小化、三权分立二
访问控制:网络访问控制三
安全审计:审计日志与留存五、六
通信完整性/保密性:TLS四
数据备份恢复七

参考依据

  • GB/T 22239-2019《信息安全技术 网络安全等级保护基本要求》(8.1.4 安全计算环境各控制点(数据库管理系统自身安全);涉客户端与服务端通信时另含 8.1.2 安全通信网络):http://openstd.samr.gov.cn/bzgk/gb/newGbInfo?hcno=BAFB47E8874764186BDB7865E8344DAF
  • GB/T 28448-2019《信息安全技术 网络安全等级保护测评要求》(测评对象边界认定、单元测评实施与结果判定:符合/部分符合/不符合/不适用):http://openstd.samr.gov.cn/bzgk/gb/newGbInfo?hcno=7E736CDF4502B6FF1258DD250AA3EC8C
  • GB/T 22240-2020《信息安全技术 网络安全等级保护定级指南》、GB/T 25070-2019《安全设计技术要求》、GB/T 28449-2018《测评过程指南》,可在全国标准信息公共服务平台检索:http://openstd.samr.gov.cn/bzgk/gb/
  • PostgreSQL 官方文档(Server Administration / Client Authentication / pg_hba.conf / pgAudit 见扩展列表):https://www.postgresql.org/docs/
  • 《网络安全等级保护测评高风险判定指引》(中关村信息安全测评联盟团体标准)——高风险情形判定口径,站内对照表:22、高风险判定指引与加固对照表
  • 命令核验说明:PostgreSQL 参数与命令以 PostgreSQL 官方文档(Server Configuration / Client Authentication / pgAudit 见官方扩展列表)核验(核验日期 2026-09-02)。六处须留意:① 旧版文章中常见 ALTER ROLE ... PASSWORD POLICY、SET PASSWORD ENCRYPTION FOR USER 等并不存在的语法,PostgreSQL 无此类命令,口令策略须通过 passwordcheck 扩展 + VALID UNTIL + 制度约束组合实现;② password_encryption 改为 scram-sha-256 后不会自动转换存量口令,必须逐账户重新 ALTER ROLE ... PASSWORD 才会以新方式存储,同时 pg_hba.conf 的认证方法也要改为 scram-sha-256,两处不同步会导致全员无法登录;③ passwordcheck 属 contrib 模块,能力有限(主要校验长度与弱口令字典,不含字符类组合与历史防重复),须辅以应用侧或制度约束,并在报告中说明;④ PostgreSQL 无内置登录失败锁定,须用 fail2ban(配合 log_connections/log_line_prefix 输出源 IP)或数据库审计系统联动实现,不得据参数缺失直接判不符合;⑤ idle_session_timeout 需 14 及以上版本,9.6~13 只能用 idle_in_transaction_session_timeout + statement_timeout 或 pgbouncer 的 server_idle_timeout/client_idle_timeout 替代并说明;⑥ ssl_min_protocol_version 需 12 及以上版本,更早版本只能靠 ssl_ciphers 排除低版本套件,核查时以 openssl s_client -tls1 握手失败作为实测证据。

关联文章