数据库安全
本节描述数据库安全相关操作
IP黑白名单和SSL加密连接
参考 服务器管理--客户端认证
章节
账号权限控制
参考 用户管理--用户权限
章节
账号有效期控制
参考 用户管理--用户权限
章节
备份恢复
参考 物理数据备份--备份恢复
章节
强烈建议开启数据库归档archive_mode
网络安全
建议系统管理员配置防火墙,只允许可信来源访问数据库端口.
passwordcheck 密码复杂度检查
此插件用于在创建或修改数据库用户密码时进行密码强度验证,可以有效防止使用弱密码。
安装配置
修改unvdbsvr.conf添加共享库 在配置文件中添加:
shared_preload_libraries = 'passwordcheck' # 添加udaudit到共享库列表
重启数据库并创建插件
unvdb=# CREATE EXTENSION passwordcheck;
CREATE EXTENSION
密码验证规则
插件将强制执行以下密码规则:
最小长度要求:密码长度必须不少于8个字符
复杂度要求:密码必须同时包含字母和非字母字符
用户名限制:密码中不能包含用户名
加密密码限制:对于已加密的密码,只能验证是否与用户名相同
使用示例
创建新用户
unvdb=# -- 不符合要求的密码示例
CREATE ROLE test_user1 PASSWORD 'short'; -- 将失败:密码太短
CREATE ROLE test_user2 PASSWORD 'onlyletters'; -- 将失败:没有非字母字符
CREATE ROLE test_user3 PASSWORD 'test_user3'; -- 将失败:包含用户名
符合要求的密码示例
CREATE ROLE test_user4 PASSWORD 'MyP@ssw0rd'; -- 成功:符合所有要求
ERROR: password is too short
ERROR: password must contain both letters and nonletters
ERROR: password must not contain user name
CREATE ROLE
unvdb=#
修改用户密码
unvdb=# -- 不符合要求的密码示例
CREATE ROLE test_user1 PASSWORD 'short'; -- 将失败:密码太短
CREATE ROLE test_user2 PASSWORD 'onlyletters'; -- 将失败:没有非字母字符
CREATE ROLE test_user3 PASSWORD 'test_user3'; -- 将失败:包含用户名
符合要求的密码示例
CREATE ROLE test_user4 PASSWORD 'MyP@ssw0rd'; -- 成功:符合所有要求
ERROR: password is too short
ERROR: password must contain both letters and nonletters
ERROR: password must not contain user name
CREATE ROLE
不符合要求的密码示例
ALTER ROLE test_user4 PASSWORD '123456'; -- 将失败:密码太短
ALTER ROLE test_user4 PASSWORD 'abcdefgh'; -- 将失败:没有非字母字符
符合要求的密码示例
ALTER ROLE test_user4 PASSWORD 'NewP@ssw0rd'; -- 成功:符合所有要求
ERROR: password is too short
ERROR: password must contain both letters and nonletters
ALTER ROLE
unvdb=#
udaudit 审计
实现DDL,DML操作的日志记录
安装
修改unvdbsvr.conf添加共享库 在配置文件中添加:
shared_preload_libraries = 'udaudit' # 添加udaudit到共享库列表
重启数据库并创建插件
unvdb=# create extension udaudit;
CREATE EXTENSION
配置审计选项
查看当前配置
unvdb=# -- 查看审计日志级别
SHOW udaudit.log;
udaudit.log
-------------
none
(1 row)
unvdb=# -- 查看审计日志输出级别
SHOW udaudit.log_level;
udaudit.log_level
-------------------
log
(1 row)
unvdb=# -- 查看其他相关配置
SHOW udaudit.log_client;
SHOW udaudit.log_catalog;
SHOW udaudit.log_parameter;
udaudit.log_client
--------------------
off
(1 row)
udaudit.log_catalog
---------------------
on
(1 row)
udaudit.log_parameter
-----------------------
off
(1 row)
修改配置
unvdb=# -- 设置审计级别(可选:DDL,FUNCTION,MISC,READ,ROLE,WRITE等)
ALTER SYSTEM SET udaudit.log = 'DDL, READ, WRITE';
-- 设置日志输出级别
ALTER SYSTEM SET udaudit.log_level = 'notice';
-- 启用客户端日志显示
ALTER SYSTEM SET udaudit.log_client = on;
-- 重新加载配置
SELECT pg_reload_conf();
ALTER SYSTEM
ALTER SYSTEM
ALTER SYSTEM
pg_reload_conf
----------------
t
(1 row)
审计功能测试
DDL审计
unvdb=# -- 创建测试表
CREATE TABLE test_audit(id int, name text);
-- 查看审计日志,将显示类似:
-- AUDIT: SESSION,1,1,DDL,CREATE TABLE,TABLE,public.test_audit,...
-- 修改表结构
ALTER TABLE test_audit ADD COLUMN email text;
-- 删除表
DROP TABLE test_audit;
NOTICE: AUDIT: SESSION,1,1,DDL,CREATE TABLE,TABLE,public.test_audit,"CREATE TABLE test_audit(id int, name text)",<not logged>
CREATE TABLE
NOTICE: AUDIT: SESSION,2,1,DDL,ALTER TABLE,TABLE,public.test_audit,ALTER TABLE test_audit ADD COLUMN email text,<not logged>
ALTER TABLE
NOTICE: AUDIT: SESSION,3,1,DDL,DROP TABLE,TABLE,public.test_audit,DROP TABLE test_audit,<not logged>
DROP TABLE
DML审计
unvdb=# -- 创建测试表
CREATE TABLE test_audit(id int, name text);
NOTICE: AUDIT: SESSION,4,1,DDL,CREATE TABLE,TABLE,public.test_audit,"CREATE TABLE test_audit(id int, name text)",<not logged>
CREATE TABLE
unvdb=# -- 插入数据
INSERT INTO test_audit VALUES(1, 'test');
-- 查询数据
SELECT * FROM test_audit;
-- 更新数据
UPDATE test_audit SET name = 'test2' WHERE id = 1;
-- 删除数据
DELETE FROM test_audit WHERE id = 1;
NOTICE: AUDIT: SESSION,5,1,WRITE,INSERT,,,"INSERT INTO test_audit VALUES(1, 'test')",<not logged>
INSERT 0 1
NOTICE: AUDIT: SESSION,6,1,READ,SELECT,,,SELECT * FROM test_audit,<not logged>
id | name
----+------
1 | test
(1 row)
NOTICE: AUDIT: SESSION,7,1,WRITE,UPDATE,,,UPDATE test_audit SET name = 'test2' WHERE id = 1,<not logged>
UPDATE 1
NOTICE: AUDIT: SESSION,8,1,WRITE,DELETE,,,DELETE FROM test_audit WHERE id = 1,<not logged>
DELETE 1
用户操作审计
unvdb=# -- 创建角色
CREATE ROLE audit_test WITH LOGIN PASSWORD 'password';
-- 授权操作
GRANT SELECT ON test_audit TO audit_test;
-- 回收权限
REVOKE SELECT ON test_audit FROM audit_test;
CREATE ROLE
GRANT
REVOKE
常用审计配置说明
udaudit.log: 指定需要审计的操作类型
DDL: 数据定义语言
FUNCTION: 函数调用
MISC: 其他操作
READ: SELECT操作
ROLE: 用户和权限操作
WRITE: INSERT/UPDATE/DELETE操作
udaudit.log_level: 指定审计日志的输出级别
debug
info
notice
warning
log
udaudit.log_client: 是否在客户端显示审计日志
on: 显示
off: 不显示
udaudit.log_catalog: 是否审计系统表操作
on: 审计
off: 不审计
审计日志
审计日志格式说明: AUDIT: [类型],[语句ID],[子语句ID],[操作类别],[命令],[对象类型],[对象名],[SQL语句]
举例:
AUDIT: SESSION,1,1,DDL,CREATE TABLE,TABLE,public.test_audit,CREATE TABLE test_audit(id int, name text)
可以通过以下方式查看审计日志:
数据库日志文件 系统日志(如果配置输出到syslog) 客户端日志(如果udaudit.log_client=on)
ud_auth_mon 登录失败锁定
此功能实现登录失败N次后锁定N分钟,有效避免密码爆破对数据库产生更大的影响.
安装
修改unvdbsvr.conf
shared_preload_libraries = 'ud_auth_mon'
创建插件
drop extension if exists ud_auth_mon;
create extension ud_auth_mon;
查看和修改配置
--Maximum number of failed login attempts before lockout
unvdb=# show ud_auth_mon.max_failed_attempts;
ud_auth_mon.max_failed_attempts
--------------------------------
3
(1 row)
--Account lockout period in minutes
unvdb=# show ud_auth_mon.lockout_period;
ud_auth_mon.lockout_period
---------------------------
15min
(1 row)
unvdb=# alter system set ud_auth_mon.max_failed_attempts = 2;
ALTER SYSTEM
unvdb=# alter system set ud_auth_mon.lockout_period = 5;
ALTER SYSTEM
unvdb=# select pg_reload_conf();
pg_reload_conf
---------------
t
(1 row)
unvdb=# show ud_auth_mon.max_failed_attempts;
ud_auth_mon.max_failed_attempts
--------------------------------
2
(1 row)
unvdb=# show ud_auth_mon.lockout_period;
ud_auth_mon.lockout_period
---------------------------
5min
(1 row)
查看初始状态
unvdb=# select * from ud_auth_mon;
rolname | unknown_user | uid | successful_attempts | last_successful_ts | total_hba_conflicts | total_auth_failures | last_failed_ts | recent_failures | lockout_until
---------+--------------+-----+---------------------+-------------------------------+---------------------+---------------------+----------------+-----------------+---------------
unvdb | f | 10 | 1 | 2025-01-03 13:24:16.032898+08 | 0 | 0 | | 0 |
(1 row)
第一次失败尝试
[user@localhost]$ ud_sql -h 192.168.4.216 -p 5678 -d unvdb -U u1 Password for user u1: wrong ud_sql: error: connection to server at “192.168.4.216”, port 5678 failed: FATAL: password authentication failed for user “u1”
第二次失败尝试
[user@localhost]$ ud_sql -h 192.168.4.216 -p 5678 -d unvdb -U u1 Password for user u1: wrong ud_sql: error: connection to server at “192.168.4.216”, port 5678 failed: FATAL: account is locked due to too many failed attempts DETAIL: Please try again after 5 minutes
查看状态:
unvdb=# select * from ud_auth_mon;
现在测试锁定期间使用正确密码
[user@localhost]$ ud_sql -h 192.168.4.216 -p 5678 -d unvdb -U u1
Password for user u1: correct_password
ud_sql: error: connection to server at "192.168.4.216", port 5678 failed: FATAL: account is locked due to too many failed attempts
DETAIL: Please try again after 4 minutes
测试解锁功能
unvdb=# select reset_auth_lockout('u1');
reset_auth_lockout
--------------------
(1 row)
unvdb=# select * from ud_auth_mon;
解锁后尝试登录
[user@localhost]$ ud_sql -h 192.168.4.216 -p 5678 -d unvdb -U u1
Password for user u1: correct_password
ud_sql (24.2, server 22.4)
Type "help" for help.
unvdb=>
恢复原始配置
alter system set ud_auth_mon.max_failed_attempts = 3;
alter system set ud_auth_mon.lockout_period = 15;
select pg_reload_conf();
show ud_auth_mon.max_failed_attempts;
show ud_auth_mon.lockout_period;