使用init_connect記錄MySQL登錄日誌

1. 相關背景

MySQL提供了一個參數init_connect用來控制當用戶登陸時默認執行指定命令,雖然會執行,但不會返回任何結果,但可以將執行的結果保存到表中記錄,我們可以利用這個特性來記錄用戶登錄數據庫的行爲日誌

2. 操作步驟

  1. 創建一張登錄日誌表,包含以下信息
    • 數據庫中對應的用戶
    • 連接數據庫的IP或主機名
    • 訪問的數據庫
    • 登錄數據庫後分配的連接ID
    • 登錄數據庫的時間
  2. 對數據庫中所有用戶都授予登錄日誌表的查詢和插入權限
    • 該步驟十分關鍵,如果用戶沒該表的相應權限,會導致設置了init_connect參數後用戶無法登錄
  3. 配置init_connect參數觸發用戶登錄時自動插入一條登錄日誌
  4. 驗證可用性

1. 創建一張登錄日誌表

CREATE TABLE `mysql`.`audit_login` (
  `ID` bigint NOT NULL AUTO_INCREMENT COMMENT '自增ID',
  `USER` varchar(128)  NOT NULL COMMENT '數據庫中的用戶',
  `HOST` varchar(64)  DEFAULT NULL COMMENT '登錄的IP',
  `DB` varchar(64)  DEFAULT NULL COMMENT '訪問的數據庫',
  `PROCESSLIST_ID` bigint NOT NULL COMMENT '用戶連接',
  `LOGIN_TIME` datetime(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '登錄時間',
  `UPDATE_TIME` datetime(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '記錄這行數據上次被修改的時間,默認等於LOGIN_TIME',
  PRIMARY KEY (`ID`),
  KEY `IDX_USER` (`USER`),
  KEY `IDX_HOST` (`HOST`),
  KEY `IDX_LOGIN_TIME` (`LOGIN_TIME`)
) ENGINE=InnoDB COMMENT "用戶登錄審計日誌表";

2. 生成對訪問日誌表的授權操作

這裏生成的授權語句會排除內部用戶和有super權限的用戶

-- 批量生成授權語句的SQL
-- 查詢權限可以不授予,可根據具體情況調整
select concat("grant select,insert on mysql.audit_login to '",user,"'@'",host,"';") grants_sql from mysql.user where user not in ('mysql.session','mysql.sys') and Super_priv='N';

-- 輸出示例
+-------------------------------------------------------------+
| grants_sql                                                  |
+-------------------------------------------------------------+
| grant select,insert on mysql.audit_login to 'zhenxing'@'%'; |
| grant select,insert on mysql.audit_login to 'bbb'@'%';      |
+-------------------------------------------------------------+

3. 配置init_connect參數

先在數據庫中用set global動態設置並驗證生效後在配置到my.cnf文件中

set global init_connect="insert into mysql.audit_login(USER,HOST,DB,PROCESSLIST_ID) values(current_user(),substring_index(user(),'@',-1),database(),connection_id());";

-- my.cnf文件中的配置方法
[mysqld]
init_connect="insert into mysql.audit_login(USER,HOST,DB,PROCESSLIST_ID) values(current_user(),substring_index(user(),'@',-1),database(),connection_id());";

4. 驗證有效性

使用沒有super權限的用戶登錄數據庫並查詢mysql.audit_login是否有記錄即可
注意:該表中的PROCESSLIST_ID對應的binlog日誌中的thread_id,可以使用這個來觀測該用戶登錄到數據庫後的修改操作,但由於binlog不記錄查詢操作,所以不支持對查詢操作的匹配.

3. 限制條件

  1. 不會記錄有super權限的用戶的登錄操作
    • 防止在不允許重啓的情況下因爲init_connect配置錯誤導致有super權限的用戶也登不上數據庫
  2. 密碼過期的用戶不會記錄也不會報錯
    • 需要給到密碼過期的用戶修改密碼的機會,不能在登錄時就報錯
  3. 只記錄登入行爲,不記錄登出行爲
  4. 不記錄登錄數據庫後的增刪改查操作
  5. 有連接池的情況下,連接會被複用,不一定能一一對應
  6. 使用價值不會太高,要細化還是需要專有的審計插件
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章