Mysql8中的无插件方式审计
作者:endzhi
需求
在mysql 8中记录用户对数据库表的操作内容,操作时间,客户端源ip地址。
在mysql5.7完美地采用MariaDB的server_audit插件来记录{时间,节点,用户,源IP,事件类型,库,语句,影响行数}等审计,但从mysql8开始已不支持该插件,同类的第三方插件也无法使用。
目前找到的方式:
[ binlog + init-connect ],binlog可以审计到所有数据记录及表结构变更相关的记录,但,不记录连接的信息,要通过额外的手段来记录,比如show full processlist;
是可得出连接信息中的process id,与binlog中的thread id进行关联分析,得到连接的信息{用户名、登录时间、源ip},为了永久记录process id,采用init-connect 方式记录到数据库表中。
1. 创建init-connect用于记录的库和表
mysql> create database mysql_access_log; mysql> create table mysql_access_log.access_log ( conn_id int(11) default null, `time` timestamp, `localname` varchar(30), `matchname` varchar(30));
2. 授权用户于该库的表mysql_access_log.accesslog有insert权限
如用户user_web
mysql> grant insert on `mysql_access_log`.`access_log` to 'user_web'@'%';
3. 配置用户登录日志插入表
my.cnf中 [mysqld] 下添加,并重启mysql生效
init-connect='insert into mysql_access_log.access_log values(connection_id(),now(),user(),current_user());'
4. 特别注意
①init-connect只记录非super权限用户,所以好好管理用户,按情况回收super权限;
②非super权限用户登录都受init-connect影响,未授权对mysql_access_log.access_log有insert权限的用户即无法登录成功!
③当重启mysql后connection_id会存在不按历史续增长而重复出现,所以查记录时注意多个重复的id记录。
5. 开启mysql-binlog日志记录
在my.cnf中 [mysqld] 下添加,并重启mysql生效
# 二进制日志 log-bin=mysql-bin # binlog-do-db=db #仅作用的库 expire_logs_days = 20 max_binlog_size = 300m
6. 从binlogi日志 取thread_id去查用户名和源ip
模拟删除book库books表中的一条记录-----过程省略!
解密mysql-bin查看内容,找到DELETE操作的thread_id号,如这里的8。
[root@localhost data]# mysqlbinlog --base64-output=decode-row -vv mysql-bin.000003 > ./mysql-bin.000003--vv.log [root@localhost data]# tail -n 30 ./mysql-bin.000003--vv.log #200712 18:24:01 server id 1 end_log_pos 1008 CRC32 0x62294de5 Query thread_id=8 exec_time=0 error_code=0 SET TIMESTAMP=1594549441/*!*/; SET @@session.character_set_client=255,@@session.collation_connection=255,@@session.collation_server=255/*!*/; #200712 18:24:01 server id 1 end_log_pos 1079 CRC32 0x0723c708 Table_map: `book`.`books` mapped to number 95 #200712 18:24:01 server id 1 end_log_pos 1187 CRC32 0xc96cc08e Delete_rows: table id 95 flags: STMT_END_F ### DELETE FROM `book`.`books` ### @1=44 /* INT meta=0 nullable=0 is_null=0 */ ### @2='XML 完全探索' /* VARSTRING(765) meta=765 nullable=1 is_null=0 */
根据thread_id号去找init-connect记录表的登录用户和源ip
[root@localhost data]# mysql -u root -p -e "select * from mysql_access_log.access_log where conn_id=8 ;" | conn_id | time | localname | matchname | +---------+---------------------+-------------------------+------------+- | 8 | 2020-07-12 18:23:41 | user_web@192.168.53.119 | user_web@% | +---------+---------------------+-------------------------+------------+-
7. 开启general-log日志记录
[ binlog + init-connect ] 方式,受限于binlog本身记录日志的局限,无法审计一些并不记录在binlog中的内容。
比如无SELECT、Connect;可同时开启mysql的general-log记录,记录执行的所有的语句的信息。
在my.cnf中 [mysqld] 下添加,并重启mysql生效
general-log=1 general_log_file = /opt/mysql/data/general_log_file.log #按你实际路径,注意权限
但存在的不足
- a. 无论所执行语句是否正确执行,都会记录,会导致大量的无用信息,后面的筛选不易操作;
- b. 当server的并发访问非常大时,log的记录会对IO产一定的影响,以致于影响server的性能;
- c. 日志文件很容易快速增长;
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。