本文目录导读:

- 方案一:使用官方扩展
pg_audit(推荐,最专业) - 方案二:使用触发器 + 审计表(自定义,灵活)
- 方案三:启用 PostgreSQL 自身日志(简单,粗粒度)
- 方案四:使用第三方工具(如 pgauditadmin 或 log_fdw)
- 最佳实践建议
PostgreSQL 的审计功能(记录谁在什么时间执行了什么操作)不像 MySQL 或 SQL Server 那样内置完善,它主要通过以下几种方式来实现,你可以根据安全合规要求和性能开销来选择合适的方案。
使用官方扩展 pg_audit(推荐,最专业)
这是 PostgreSQL 社区最推荐的审计方案,它基于 PostgreSQL 的日志系统,但提供了细粒度的控制,可以记录 DDL、DML、SELECT 等不同类型语句。
安装
- 如果使用 apt/yum 安装的 PostgreSQL:安装
postgresql-contrib包(通常附带pg_audit)。 - 从源码编译:在编译时加上
--with-pgaudit选项。 - 检查是否已安装:
SELECT * FROM pg_available_extensions WHERE name = 'pgaudit';
配置
需要修改 postgresql.conf 文件并重启或重新加载配置。
-
加载扩展:
shared_preload_libraries = 'pgaudit' # 必须重启
-
设置日志参数:
# 必须设置为 ddl 或以上级别,才能记录在日志中 log_statement = 'none' # pg_audit 会接管日志,建议设为 none,避免重复 logging_collector = on # 收集日志文件 log_directory = 'pg_log' # 日志存放目录 log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # pg_audit 参数 pgaudit.log = 'write, ddl' # 记录写入和DDL操作 pgaudit.log_level = 'notice' # 日志级别,通常为 notice pgaudit.log_catalog = off # 是否记录系统表操作 pgaudit.log_relation = on # 是否记录表名 pgaudit.log_client = on # 是否记录客户端信息 pgaudit.log_statement_once = off # 每条语句只记录一次
-
配置项解释:
pgaudit.log:核心配置,值可以是none,all,write,ddl,read,function,role,misc等的组合。'write, ddl, read'。pgaudit.log_relation:如果为on,会记录具体的表名(如INSERT INTO t1),否则只记录语句类型。
应用配置
编辑配置文件后,重启 PostgreSQL 服务或使用:
SELECT pg_reload_conf();
验证
执行一条 DDL 语句:
CREATE TABLE test_audit (id int);
查看 PostgreSQL 日志文件,你会看到类似以下的记录:
2025-01-20 14:30:00.123 UTC [12345] LOG: AUDIT: SESSION,1,1,DDL,CREATE TABLE,,,CREATE TABLE test_audit (id int);,<not logged>
这意味着审计已生效。
更精细的控制(对象级审计)
pg_audit 允许你创建“审计角色”,只审计特定对象的操作。
-- 创建一个专门的审计角色 CREATE ROLE auditor_role; COMMENT ON ROLE auditor_role IS '审计角色'; -- 只审计某些敏感表的操作 -- 需要结合行级安全策略或触发器来实现更复杂的对象过滤,pg_audit 本身不直接支持按表名过滤(仅支持按角色过滤)。
使用触发器 + 审计表(自定义,灵活)
适合需要长期存储审计记录,或者需要自定义审计字段(如应用程序上下文)的场景。
创建审计表
CREATE TABLE audit_log (
id BIGSERIAL PRIMARY KEY,
table_name TEXT NOT NULL, -- 被修改的表
operation TEXT NOT NULL, -- INSERT, UPDATE, DELETE
old_row_data JSONB, -- 旧行数据
new_row_data JSONB, -- 新行数据
changed_by TEXT NOT NULL, -- 执行用户
client_addr INET, -- 客户端IP
session_user TEXT, -- 会话用户
application_name TEXT, -- 应用名称
change_time TIMESTAMPTZ DEFAULT NOW(),
query TEXT -- 完整SQL
);
创建审计函数
CREATE OR REPLACE FUNCTION audit_trigger_function()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO audit_log (
table_name,
operation,
old_row_data,
new_row_data,
changed_by,
client_addr,
session_user,
application_name,
query
) VALUES (
TG_TABLE_NAME,
TG_OP,
CASE WHEN TG_OP IN ('UPDATE','DELETE') THEN row_to_json(OLD)::jsonb ELSE NULL END,
CASE WHEN TG_OP IN ('INSERT','UPDATE') THEN row_to_json(NEW)::jsonb ELSE NULL END,
current_user,
inet_client_addr(),
session_user,
current_setting('application_name'),
current_query()
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
将触发器附加到敏感表
CREATE TRIGGER t_audit_employees
BEFORE INSERT OR UPDATE OR DELETE ON employees
FOR EACH ROW
EXECUTE FUNCTION audit_trigger_function();
优点:非常灵活,可以自定义记录内容。
缺点:
- 对性能有影响(每条语句触发函数 + JSON 序列化)。
- 需要为每张被审计的表手动创建触发器。
- 无法审计
SELECT(SELECT不触发触发器)。
启用 PostgreSQL 自身日志(简单,粗粒度)
如果只是临时排查,不需要长期保存,可以使用 PostgreSQL 内置的日志功能。
配置 postgresql.conf
logging_collector = on log_statement = 'all' # 记录所有SQL,或者 'ddl' / 'mod' log_duration = on # 记录语句执行时间 log_line_prefix = '%m [%p] %u@%d %r ' # 包含时间、用户、数据库、主机名
查看日志
所有 SQL 语句会写入 pg_log/ 目录下的日志文件。
缺点:
- 所有语句都会记录,日志量巨大,不适合生产环境长期开启。
- 无法记录更新前后的数据值。
- 区分度差,无法仅审计特定表。
使用第三方工具(如 pgauditadmin 或 log_fdw)
- pgauditanalyze:一个开源工具,能解析
pg_audit生成的日志,生成更友好的报告。 - log_fdw:允许你在 PostgreSQL 中以外部表的形式查询数据库日志文件。
最佳实践建议
- 生产环境推荐:使用
pg_audit扩展,它是专门为审计设计的,性能开销可控,并且符合很多安全审计标准(如 SOX、PCI-DSS)。 - 何时用触发器:当你需要记录行级数据变更前的值(如更新前的数据),或者需要自定义审计字段(如“订单金额大于1000时记录”),并且数据量不大时。
- 何时用日志:仅用于临时调试,或作为补充记录(配合
pg_audit的记录要完整一些,但log_statement可以记录到更细的级别)。 - 注意事项:
- 审计日志文件会快速膨胀,需要配置日志轮转(
log_rotation_age和log_rotation_size)。 - 审计表本身也要考虑安全性:将其放在单独的表空间,并限制对
audit_log表的访问权限,防止审计记录被恶意删除或修改。 - 定期对审计表进行分区,清理过期记录。
- 审计日志文件会快速膨胀,需要配置日志轮转(
- 长期、合规审计 →
pg_audit扩展。 - 追踪数据变更(谁改了什么值) → 触发器 + 审计表。
- 临时排查问题 → 开启
log_statement = 'all'。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播