数据库安全
本节描述数据库安全相关操作
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;
ud_tde 透明加密
透明存储加密方式是一种保护数据库中静态数据的加密技术,使数据在存储时自动加密,有助于防止未授权访问和数据泄露。
安装
修改unvdbsvr.conf添加共享库 在配置文件中添加:
shared_preload_libraries = 'ud_tde' # 添加ud_tde到共享库列表
重启数据库并创建插件
unvdb=# create extension ud_tde;
CREATE EXTENSION
配置TDE选项
查看当前配置
unvdb=# -- 显示数据库的主密钥信息
SELECT * FROM ud_tde_principal_key_info();
principal_key_name | key_provider_name | key_provider_id | principal_key_internal_name | principal_key_version | key_createion_time
--------------------+-------------------+-----------------+-----------------------------+-----------------------+-------------------------------
my-principal-key | file | 1 | my-principal-key_2 | 2 | 2024-12-12 15:12:26.017167+08
(1 row)
创建密钥配置
--使用本地文件创建一个新的数据库密钥提供者来存储主密钥。
--函数定义
ud_tde_add_key_provider_file(provider_name VARCHAR(128), file_path TEXT)
--用法
SELECT ud_tde_add_key_provider_file('provider-name','/path/to/the/keyring/data.file');
--示例
SELEC ud_tde_add_key_provider_file('file','myudkeyring');
--使用指定的密钥提供者设置数据库的主密钥
--函数定义
ud_tde_set_principal_key(principal_key_name VARCHAR(255), provider_name VARCHAR(255), ensure_new_key BOOLEAN DEFAULT FALSE)
--用法
SELECT ud_tde_set_principal_key('name-of-the-principal-key', 'provider-name');
--用例
SELECT ud_tde_set_principal_key('my-principal-key','file');
--创建指定主密钥的新版本,并更新数据库,使其使用新的主密钥版本
--函数定义
ud_tde_rotate_key(new_principal_key_name VARCHAR(255) DEFAULT NULL, new_provider_name VARCHAR(255) DEFAULT NULL, ensure_new_key BOOLEAN DEFAULT TRUE)
--用法
SELECT ud_tde_rotate_principal_key('name-of-the-new-principal-key', 'name-of-the-new-provider');
--使用同样的提供者,创建新的主密钥
SELECT ud_tde_rotate_principal_key('name-of-the-new-principal-key', NULL);
--使用同样的主密钥到新的提供者
SELECT ud_tde_rotate_principal_key(NULL, 'name-of-the-new-provider');
--使用同样的提供者,更新数据库当前主密钥的版本
SELECT ud_tde_rotate_principal_key();
--用例
SELECT ud_tde_rotate_principal_key();
unvdb=# -- 查看其他相关配置
SELECT * FROM ud_tde_principal_key_info();
表透明加密配置
--创建加密表
--需要在表的定义最后加上 USING ud_tde_basic关键字。如下所示:
CREATE TABLE tablename table definition USING ud_tde_basic;
--示例
CREATE TABLE tb_tel(id int, name varchar(20),tel varchar(20)) USING ud_tde_basic;
--修改加密状态
ALTER TABLE tablename SET access method ud_tde_basic;
--修改为非加密状态
ALTER TABLE tablename SET access method heap;
--示例
CREATE TABLE tb (id INT);
ALTER TABLE tb SET access method ud_tde;
ALTER TABLE tb SET access method heap;
--查看表的机密状态
SELECT udtde_is_encrypted('tablename');
SELECT udtde_is_encrypted('schema.tablename');
--测试加密的另外验证方法
CREATE TABLE tb_tel(id int, name varchar(20),tel varchar(20)) USING ud_tde_basic;
INSERT INTO tb_tel values(1, 'laochen','13812348888'),(2, 'laowang','13812346666');
SELECT pg_relation_filepath('tb_tel');
pg_relation_filepath
----------------------
base/5/16411
(1 row)
hexdump -c base/5/16411 |grep c
--查看数据文件已经无法显示完整的字符,说明表tb_tel已经被加密。
TDE功能测试
完整测试示例
SELECT ud_tde_add_key_provider_file('file3','myudkeyring3'); --使用本地文件创建一个新的数据库密钥提供者来存储主密钥。
SELECT ud_tde_set_principal_key('my-principal-key3','file3');--使用指定的密钥提供者设置数据库的主密钥
SELECT * FROM ud_tde_principal_key_info(); --查看密钥信息
SELECT ud_tde_rotate_key('my-principal-key4','file3') --更改主密钥(可选)
CREATE TABLE tb_tel_tde(id int, name varchar(20),tel varchar(20)) USING ud_tde_basic; --创建加密表
insert into tb_tel_tde values(1,'songxd','15801402675'); --插入表数据
SELECT * FROM ud_tde_principal_key_info(); --查看密钥信息
SELECT udtde_is_encrypted('tb_tel_tde'); --查看表是否加密
透明存储加密(TDE)与其他功能结合
主备集群的透明存储加密:
对于表加密。九有数据库集群支持表透明存储加密。如果主库使用表加密,相关信息会自动同步到备库中。主库如果修改加密密钥,集群会将密钥信息自动同步到备库中。
透明存储加密与接口的结合:
透明存储加密对九有数据库程序接口调用的操作没有任何影响,对应用程序透明。除了传输安全部分,透明存储操作对应用接口透明。
使用透明存储加密的注意事项
• 为加密数据设置单独的安全管理员。
• 确定数据库中数据的敏感度,所需要的保密和风险级别。不敏感的数据不需要进行加密操作。
• 管理数据文件的安全性及时删除一些加密前的文件,旧的文件可能存在明文数据。如果特权操作系统用户绕过数据库访问控制,可能直接获取数据信息。为避免这种项目,可以将加密的对象移动到新的表空间中,然后删除原来的表空间文件。