首页 > 数据库 > 数据库开发技术 > 一文搞懂MySQL开源审计功能

首先,为什么需要数据库审计?
)其次,以企业安全和等保测评这两方面体现审计的重要性。
企业的发展壮大和可持续发展离不开审计的保驾护航。

金融及政府等有严格法律法规要求的行业。数据安全审计能够按照标准要求提供完全对应条例的审计信息,确保网络合规性。

再次,本文主要以MySQL数据库作为分析对象,那MySQL有哪些审计工具呢?
详见图文,已经简要说明工具的来源、类型、基本原理等信息。

由于环境和经费问题,笔者主要选择三个适用性比较好的工具进行演示,分别是init-connect+binlog、McAfee插件和MariaDB插件,通过三者比较以下事件类型能否被记录作为审计的功能点评估。

01
测试案例
### 1. 创建数据库
create database test_aud;
use test_aud;
### 2. 创建用户
create user 'xixi'@'%' identified by "123456";
create user 'haha'@'%' identified by "123456";
### 3. 授予权限
GRANT ALL PRIVILEGES ON test_aud.* TO 'xixi'@'%';
grant select,insert,update,delete on test_aud.* to 'haha'@'%';
revoke select,insert,update,delete on test_aud.* from 'haha'@'%';
### init-connect使用xixi用户进行后续操作。
### 4. 创建测试表
CREATE TABLE `t_audit` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`item_name` varchar(30) NOT NULL COMMENT '商品名称',
`price` int(11) NOT NULL COMMENT '价格',
`comment` varchar(30) NOT NULL COMMENT '评价',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
### 5. DML操作
insert into t_audit values (1,'Apple',300,'非常棒');
insert into t_audit values (2,'Banana',400,'好吃');
insert into t_audit values (3,'Orange',500,'不错');
show table status like '%t_audit%';
select * from t_audit;
update t_audit set comment='质量好' where id =2 ;
select * from t_audit;
delete from t_audit where id = 3;
### 6. Alter操作
ALTER TABLE `test_aud`.`t_audit` MODIFY COLUMN `comment` varchar(50) CHARACTER SET utf8mb4 NOT NULL COMMENT '评价' AFTER `price`;
ALTER TABLE `test_aud`.`t_audit` ADD COLUMN `user` varchar(30) NOT NULL COMMENT '用户' AFTER `comment`;
desc `test_aud`.`t_audit`;
show create table `test_aud`.`t_audit`;
### 7. 还原环境
truncate table t_audit;
drop table t_audit;
drop database test_aud;
drop user 'xixi'@'%';
drop user 'haha'@'%';理论上,测试案例的每一行SQL都应该被记录,少一行都意味着审计功能的缺陷。接下来要开始测试了,过程还是挺花时间的。
02
init-connect + binlog
1. 介绍链接
https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_init_connect
官网说明:为什么init-connect不能审计超级用户呢?
对于具有SUPER权限的用户,不会执行init_connect的内容。这样做是为了让init_connect的错误不会阻止所有客户端连接。
例如,该值可能包含有语法错误的语句,从而导致客户端连接失败。对于超级特用户,不执行init_connect,可以使他们打开连接并修复init_connect值。
设计MySQL的哥哥姐姐果然是智慧的!
create database test_audlog;
use test_audlog;
create table test_audlog.access_log ( id int(11) primary key auto_increment, Conn_id int, ConnUserName varchar(50), PrivMatchName varchar(50), LoginTime timestamp);root@localhost:mysql.sock [test_audlog]>desc test_audlog.access_log;
+---------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| Conn_id | int(11) | YES | | NULL | |
| ConnUserName | varchar(32) | YES | | NULL | |
| PrivMatchName | varchar(32) | YES | | NULL | |
| LoginTime | timestamp | YES | | NULL | |
+---------------+-------------+------+-----+---------+----------------+保证所有的用户对此表有insert权限
insert into mysql.db(host,db,user,Insert_priv) values('%','test_audlog','','Y');
flush privileges;或者,通过命令查询用户需要授予的权限。
mysql> select concat("grant insert on test_audlog.access_log to '",user,"'@'",host,"';") from mysql.user;
grant insert on test_audlog.access_log to 'haha'@'%';
grant insert on test_audlog.access_log to 'xixi'@'%';
binlog必须配置。
### 配置文件添加以下配置
init-connect='insert into test_audlog.access_log (Conn_id,ConnUserName,PrivMatchName,LoginTime) values (connection_id(),user(),current_user(),now());'
log_bin=/mysql/log/3306/binlog/mysql-bin
log_bin_index=/mysql/log/3306/binlog/mysql-bin.index
### 重启MySQL数据库
service mysql restart审计表信息。
root@localhost:mysql.sock [test_aud]>select * from test_audlog.access_log;
+----+---------+----------------------+---------------+---------------------+
| id | Conn_id | ConnUserName | PrivMatchName | LoginTime |
+----+---------+----------------------+---------------+---------------------+
| 4 | 11 | xixi@localhost | xixi@% | 2021-10-03 22:05:17 |
| 5 | 12 | haha@localhost | haha@% | 2021-10-03 22:05:27 |
| 6 | 13 | xixi@localhost | xixi@% | 2021-10-03 22:05:47 |
| 7 | 22 | xixi@192.168.117.133 | xixi@% | 2021-10-03 22:41:17 |
+----+---------+----------------------+---------------+---------------------+binlog的日志信息。
mysqlbinlog --start-datetime='2021-10-03 22:00:00' --stop-datetime='2021-10-03 22:08:00' /mysql/log/3306/binlog/mysql-bin.000008 |grep -Ei 'create|alter|truncate|drop|show|select|insert|update|delete|grant|revoke' -B 2

6. 小结
init-connect + binlog从审计的类型来看,基本上该有的都有。
不足之处有以下几点:
无法将连接信息与binlog的记录一一对应,需要手工关联。
无法审计超级用户。不排除有些应用使用root用户或者超级用户,针对此点,云平台数据库不开放root用户是明智的选择。
挖掘少量日志可行,但是海量信息就够呛了。而且挖掘出来的信息也需要进行存储,既然如此,为何不一开始就选择能够额外存放的插件呢?
审计表的连接信息可以被有权限的用户进行篡改,若清空审计表后,仅靠binlog日志无法承担审计的角色。
binlog日志没有查询记录,哪些敏感信息被读取无从考察。
03
McAfee 插件
1. 下载插件
https://github.com/mcafee/mysql-audit
[root@MYS-DB01 Package]# ls
audit-plugin-mysql-5.7-1.1.9-974-linux-x86_64.zip
[root@MYS-DB01 Package]# unzip audit-plugin-mysql-5.7-1.1.9-974-linux-x86_64.zip[root@MYS-DB01 lib]# cp libaudit_plugin.so /usr/local/mysql/lib/plugin/
[root@MYS-DB01 plugin]# chmod 755 libaudit_plugin.so
[root@MYS-DB01 ~]# chown -R mysql:mysql /mysql/log/3308/audit
[root@MYS-DB01 ~]# chmod -R 755 /mysql/log/3308/auditmysql> INSTALL PLUGIN AUDIT SONAME 'libaudit_plugin.so';
mysql> show global status like 'AUDIT_version';
+---------------+-----------+
| Variable_name | Value |
+---------------+-----------+
| Audit_version | 1.1.9-974 |
+---------------+-----------+
mysql> select * from information_schema.plugins where plugin_name='AUDIT'\G
*************************** 1. row ***************************
PLUGIN_NAME: AUDIT
PLUGIN_VERSION: 1.0
PLUGIN_STATUS: ACTIVE
PLUGIN_TYPE: AUDIT
PLUGIN_TYPE_VERSION: 4.1
PLUGIN_LIBRARY: libaudit_plugin.so
PLUGIN_LIBRARY_VERSION: 1.6
PLUGIN_AUTHOR: McAfee Inc
PLUGIN_DESCRIPTION: AUDIT plugin, creates a file mysql-audit.log to log activity
PLUGIN_LICENSE: GPL
LOAD_OPTION: ON先通过动态加载插件的方式,再在配置文件添加数据库能够识别的参数。
### 1. McAfee 插件
plugin-load=AUDIT=libaudit_plugin.so
### McAfee 参数配置
audit_json_file=on
audit_json_log_file=/mysql/log/3308/audit/mysql-audit.json
audit_record_cmds='create,drop,alter,truncate,grant,insert,delete,update,show,select,connect,quit'以Json的形式记录文件。
root@localhost:mysql.sock [(none)]>show variables like 'audit_json%';
+---------------------------------+-----------------------------------------------------+
| Variable_name | Value |
+---------------------------------+-----------------------------------------------------+
| audit_json_file | ON |
| audit_json_file_bufsize | 1 |
| audit_json_file_flush | OFF |
| audit_json_file_retry | 60 |
| audit_json_file_sync | 0 |
| audit_json_log_file | /mysql/log/3308/audit/mysql-audit.json |
| audit_json_socket | OFF |
| audit_json_socket_name | /var/run/db-audit/mysql.audit__mysql_data_3308_3308 |
| audit_json_socket_retry | 10 |
| audit_json_socket_write_timeout | 1000 |
+---------------------------------+-----------------------------------------------------+root@localhost:mysql.sock [(none)]>show variables like 'audit_re%';
+-------------------+----------------------------------------------------------------------------------+
| Variable_name | Value |
+-------------------+----------------------------------------------------------------------------------+
| audit_record_cmds | connect,create,alter,truncate,drop,select,show,insert,update,delete,grant,revoke |
| audit_record_objs | |
+-------------------+----------------------------------------------------------------------------------+
这个是白名单,以逗号隔开用户名写入配置,该用户就不会被审计。
root@localhost:mysql.sock [(none)]>show variables like '%audit_whitelist_users%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| audit_whitelist_users | |
+-----------------------+-------+在 my.cnf 中 [mysqld] 下添加 audit_uninstall_plugin=1,重启mysql。执行两次 "uninstall plugin audit" 即可卸载。
mysql> uninstall plugin audit;
ERROR 1620 (HY000): Uninstall AUDIT plugin must be called again to complete
mysql> uninstall plugin audit;
Query OK, 0 rows affected, 1 warning (0.01 sec)没有密集恐惧症的亲可以点开看看。

信息量大,即日志体积相对来说会比较大,需要更多的存储空间。
记录了一些无关要紧的信息,而且缺少了一些重要的信息,比如,create、drop、alter操作等等。表若被drop了,也不知道是谁干的,这能忍?
04
MariaDB 插件
1. 下载插件
链接1:https://mirrors.tuna.tsinghua.edu.cn/mariadb/
链接2:https://mariadb.com/kb/en/mariadb-server-10-5-12/
参数说明:https://mariadb.com/kb/en/mariadb-audit-plugin-options-and-system-variables
[root@MYS-DB01 MySQL]# tar -zxvf mariadb-10.5.12-linux-x86_64.tar.gz[root@MYS-DB01 plugin]# cp server_audit.so /mysql/software/mysql-5.7.30/lib/plugin/root@localhost:mysql.sock [(none)]>install plugin server_audit soname 'server_audit.so';跟随MariaDB数据库版本信息,查看审计类型。
root@localhost:mysql.sock [(none)]>select * from information_schema.plugins where plugin_name='SERVER_AUDIT'\G
*************************** 1. row ***************************
PLUGIN_NAME: SERVER_AUDIT
PLUGIN_VERSION: 1.4
PLUGIN_STATUS: ACTIVE
PLUGIN_TYPE: AUDIT
PLUGIN_TYPE_VERSION: 4.1
PLUGIN_LIBRARY: server_audit.so
PLUGIN_LIBRARY_VERSION: 1.4
PLUGIN_AUTHOR: Alexey Botchkov (MariaDB Corporation)
PLUGIN_DESCRIPTION: Audit the server activity
PLUGIN_LICENSE: GPL
LOAD_OPTION: ON先通过动态加载插件的方式,再在配置文件添加数据库能够识别的参数。参数相关介绍见注释。笔者开启了轮询,每个审计日志大小1GB,防止单个文件无限扩展。
server_audit_logging = ON # 开启日志记录,默认是关闭
server_audit = FORCE_PLUS_PERMANENT # 防止插件被卸载
server_audit_file_rotate_now = ON # 是否强制切割审计日志
server_audit_file_rotate_size = 1G # 定义切割审计日志的文件大小1073741824=1GB
server_audit_file_rotations = 999 # 定义审计日志的轮询个数,0=不轮询,MAX=999
server_audit_events = CONNECT,QUERY,QUERY_DDL,QUERY_DML,QUERY_DCL # 参考官网配置
server_audit_file_path = /mysql/log/3308/audit/server_audit.log # 审计日志路径
#server_audit_incl_users = root # 只审计某个用户server_audit_logging=ON才能开启审计,仅靠安装插件是不能开启审计的。
root@localhost:mysql.sock [(none)]>show variables like 'server_audit%';
+-------------------------------+---------------------------------------------+
| Variable_name | Value |
+-------------------------------+---------------------------------------------+
| server_audit_events | CONNECT,QUERY,QUERY_DDL,QUERY_DML,QUERY_DCL |
| server_audit_excl_users | |
| server_audit_file_path | /mysql/log/3308/audit/server_audit.log |
| server_audit_file_rotate_now | ON |
| server_audit_file_rotate_size | 1073741824 |
| server_audit_file_rotations | 999 |
| server_audit_incl_users | |
| server_audit_loc_info | |
| server_audit_logging | ON |
| server_audit_mode | 1 |
| server_audit_output_type | file |
| server_audit_query_log_limit | 1024 |
| server_audit_syslog_facility | LOG_USER |
| server_audit_syslog_ident | mysql-server_auditing |
| server_audit_syslog_info | |
| server_audit_syslog_priority | LOG_INFO |
+-------------------------------+---------------------------------------------+
16 rows in set (0.00 sec)
参考MariaDB官网信息,什么版本可以开启哪些对应的审计事件。


通过MariaDB版本了解插件可以开启的审计事件类型。
root@localhost:mysql.sock [(none)]>show variables like 'server_audit_events';
+---------------------+---------------------------------------------+
| Variable_name | Value |
+---------------------+---------------------------------------------+
| server_audit_events | CONNECT,QUERY,QUERY_DDL,QUERY_DML,QUERY_DCL |
+---------------------+---------------------------------------------+把需要审计的用户以逗号的形式隔开写入配置。这里与McAfee是相反的。
root@localhost:mysql.sock [(none)]>show variables like 'server_audit_incl_users';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| server_audit_incl_users | |
+-------------------------+-------+在数据库层面执行server_audit,并且删除配置文件相关信息。
mysql> UNINSTALL PLUGIN server_audit;信息量不是很多,比较直观。

审计的操作类型较为全面,简洁明了。
若硬要鸡蛋里挑骨头,那就得看看性能方面。
06
总结

从功能方面比较,笔者更加倾向于MariaDB插件。但除了功能外,还要考虑性能方面!
那么下文将分享有关审计的性能测试,主要根据等保要求进行,其中涉及sysbench、Python制图等。有兴趣的同学们,可以关注下喔!

此外,由于笔者的技术水平有限,本文的总结和测试结果难免考虑不周,如有侵权或者不妥之处,请联系,谢谢!
参考资料
阿里云 | 企业上云等保三级合规
腾讯云 | 腾讯云数据安全审计(Data Security Audit,DSAudit)
葫芦娃集团 | 为什么一定要做数据库审计
书籍 |《MySQL DBA工作笔记》
其他 | 见本文链接
· Python系列 | 推荐 ·
· 自动化运维系列 | 推荐 ·
自动化运维实战五 | 【演示】3分钟一键部署Mysql数据库
自动化运维实战四 | 【实现】Mysql一键部署的前后端交互
自动化运维实战三 | 【规划】Mysql一键部署的数据模型
自动化运维实战二 | 【构思】Mysql一键部署的界面
自动化运维实战一 | 【模板】 套用精美模板演示登陆界面

喜欢就点个 在看 呀!
原文作者:Python自动化运维;如有侵权,请联系管理员删除。