防火墙规则表 - xiaoboluo768/mysql-system-schema GitHub Wiki

  • 插件安装
# 5.7.13版本之前的安装方式
root@localhost : (none) 08:58:55> INSTALL PLUGIN firewall SONAME 'firewall.so';
Query OK, 0 rows affected (0.00 sec)

# 5.7.13及其之后版本的安装方式,导入$basedir/share目录下的linux_install_firewall.sql 文件,另外,在MySQL 5.7.21之前,mysql系统库下的两个表是MyISAM引擎,从5.7.21版本开始改为InnoDB引擎,如果已经安装了MyISAM引擎则可以使用alter语句修改为InnoDB引擎
## 文件内容
[root@localhost ~]# cat /usr/local/mysql/share/linux_install_firewall.sql 
# Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
# Install firewall tables
USE mysql;
CREATE TABLE IF NOT EXISTS mysql.firewall_whitelist( USERHOST VARCHAR(80) NOT NULL, RULE text NOT NULL) engine= InnoDB;
CREATE TABLE IF NOT EXISTS mysql.firewall_users( USERHOST VARCHAR(80) PRIMARY KEY, MODE ENUM ('OFF', 'RECORDING', 'PROTECTING', 'RESET', 'DETECTING') DEFAULT 'OFF') engine=InnoDB;

INSTALL PLUGIN mysql_firewall SONAME 'firewall.so';
INSTALL PLUGIN mysql_firewall_whitelist SONAME 'firewall.so';
INSTALL PLUGIN mysql_firewall_users SONAME 'firewall.so';

CREATE FUNCTION set_firewall_mode RETURNS STRING SONAME 'firewall.so';
CREATE FUNCTION normalize_statement RETURNS STRING SONAME 'firewall.so';
CREATE FUNCTION mysql_firewall_flush_status RETURNS STRING SONAME 'firewall.so';
CREATE AGGREGATE FUNCTION read_firewall_whitelist RETURNS STRING SONAME 'firewall.so';
CREATE AGGREGATE FUNCTION read_firewall_users RETURNS STRING SONAME 'firewall.so';
delimiter //
CREATE PROCEDURE sp_set_firewall_mode (IN arg_userhost VARCHAR(80), IN arg_mode varchar(12))
BEGIN
DECLARE result VARCHAR(80);
IF arg_mode = "RECORDING" THEN
  SELECT read_firewall_whitelist(arg_userhost,FW.rule) FROM mysql.firewall_whitelist FW WHERE userhost = arg_userhost;
END IF;
SELECT set_firewall_mode(arg_userhost, arg_mode) INTO result;
IF arg_mode = "RESET" THEN
  SET arg_mode = "OFF";
END IF;
IF result = "OK" THEN
  INSERT IGNORE INTO mysql.firewall_users VALUES (arg_userhost, arg_mode);
  UPDATE mysql.firewall_users SET mode=arg_mode WHERE userhost = arg_userhost;
ELSE
  SELECT result;
END IF;
IF arg_mode = "PROTECTING" OR arg_mode = "OFF" OR arg_mode = "DETECTING" THEN
  DELETE FROM mysql.firewall_whitelist WHERE USERHOST = arg_userhost;
  INSERT INTO mysql.firewall_whitelist SELECT USERHOST,RULE FROM INFORMATION_SCHEMA.mysql_firewall_whitelist WHERE USERHOST=arg_userhost;
END IF;
END //

CREATE PROCEDURE sp_reload_firewall_rules(IN arg_userhost VARCHAR(80))
BEGIN
  SELECT set_firewall_mode(arg_userhost, "RESET") AS 'Result';
  SELECT read_firewall_whitelist(arg_userhost,FW.rule) AS 'Result' FROM mysql.firewall_whitelist FW WHERE FW.userhost=arg_userhost;
END //
delimiter ;

## 导入
[root@localhost ~]# mysql -uroot -pletsg0 < /usr/local/mysql/share/linux_install_firewall.sql 

## 查看mysql下的持久表,这两张持久表只能被有权限的用户访问
root@localhost : mysql 01:05:48> show tables like '%fire%';
+--------------------------+
| Tables_in_mysql (%fire%) |
+--------------------------+
| firewall_users |
| firewall_whitelist |
+--------------------------+
2 rows in set (0.00 sec)

## 查看information_schema下的内存临时表,该内存临时表可以被任何用户访问
root@localhost : mysql 02:11:17> show tables from information_schema like '%fire%';
+---------------------------------------+
| Tables_in_information_schema (%fire%) |
+---------------------------------------+
| MYSQL_FIREWALL_WHITELIST |
| MYSQL_FIREWALL_USERS |
+---------------------------------------+
2 rows in set (0.00 sec)
  • 新增系统变量
# 系统参数变量
root@localhost : mysql 01:06:12> show variables like '%fire%';
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| mysql_firewall_mode | ON |  #默认情况下,防火墙插件安装好之后就会启用,该变量为动态变量
| mysql_firewall_trace | OFF |  # 默认为OFF,当设置为ON时,对于防护模式下,被拒绝的语句会被写入到错误日志文件中,动态变量
+----------------------+-------+
2 rows in set (0.01 sec)

# 系统状态变量
root@localhost : mysql 01:06:23> show status like '%fire%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Firewall_access_denied | 0 |  # 被拒绝的语句次数
| Firewall_access_granted | 0 | # 被允许的语句次数,实测该计数器会把允许和拒绝的请求一并计数,不要误以为是该变量有BUG,其实不是,因为客户端就算执行被拒绝的语句,客户端每次也会发送一次select @@version_comment的查询,而该语句最后都是会被允许的,后续会专门提到这个问题
| Firewall_access_suspicious | 0 |  # 在检测模式下被判定为可疑的语句,被记录到错误日志中的次数
| Firewall_cached_entries | 0 | # 在记录模式下被缓存记录的语句次数,不包含重复计数,该状态变量与information_schema下的临时白名单记录表的行数对应
+----------------------------+-------+
4 rows in set (0.00 sec)
  • 如果需要卸载firewall插件,则可以使用如下语句手动卸载
DROP TABLE mysql.firewall_whitelist;
DROP TABLE mysql.firewall_users;
UNINSTALL PLUGIN mysql_firewall;
UNINSTALL PLUGIN mysql_firewall_whitelist;
UNINSTALL PLUGIN mysql_firewall_users;
DROP FUNCTION set_firewall_mode; 
DROP FUNCTION normalize_statement;
DROP FUNCTION read_firewall_whitelist;
DROP FUNCTION read_firewall_users;
DROP FUNCTION mysql_firewall_flush_status;
DROP PROCEDURE mysql.sp_set_firewall_mode;
DROP PROCEDURE mysql.sp_reload_firewall_rules;
  • MySQL企业版中包含的MySQL企业防火墙插件,它是一种应用程序级防火墙,它允许数据库管理员根据白名单进行匹配来允许或拒绝执行哪些SQL语句。 这有助于强化MySQL服务器抵御SQL注入等攻击、或抵御其他非正常工作负载的程序的查询尝试。
  • 每个在防火墙中注册的MySQL帐户都有自己独立的语句白名单,这些白名单根据每个账号量身定制(其实就是在白名单记录表中每行记录都有账号对应)。 对于给定帐户,防火墙可以在记录、保护、检测模式下运行(firewall的三种运行模式,这三种模式的含义详见下文),在记录模式下可训练被接受的语句,以便在防护模式下主动防范一些不可接受的语句或自动检测一些不可接受的语句。以下是防火墙如何在每种模式下处理传入语句的流程
  • 首先,语句从客户端接收到之后,会被进行标准化格式解析(跟performance_schema里的digest功能类似,且也是使用max_digest_length变量来截取语句长度进行计算)
  • 然后,被标准个格式解析的语句进入防火墙
  • 检查用户防火墙模式,如果用户的防火墙模式为OFF或者未在防火墙中注册过(在防火墙中注册过的用户在information_schema.MYSQL_FIREWALL_users和mysql.firewall_users表中都会有记录),则语句直接执行,否则防火墙检查来访用户在firewall中配置的访问模式:

* 如果用户的防火墙模式配置为RECORDING(记录模式),则防火墙允许用户任何正常访问,且把用户正常访问语句的标准化格式记录到information_schema中的MYSQL_FIREWALL_WHITELIST表缓存起来,如果在information_schema下的缓存表记录成功,则状态变量Firewall_cached_entries+1

* 如果用户的防火墙模式配置为PROTECTING(防护模式),则防火墙根据mysql.firewall_whitelist表中记录白名单语句进行匹配,如果未匹配到,则拒绝访问(如果变量mysql_firewall_trace=ON,则记录被拒绝的语句到错误日志中),同时状态变量 Firewall_access_denied+1。如果匹配成功,则执行语句,同时状态变量Firewall_access_granted+1(要注意:mysql.firewall_whitelist表中记录来自在RECORDING模式下学习训练时information_schema下的缓存表,缓存表中的记录在用户防火墙模式从RECORCING模式切换为PROTECTING模式时被同步到持久表mysql.firewall_whitelist中)

* 如果用户的防火墙模式配置为DETECTING(检测模式),则防火墙不拒绝任何语句执行,但会根据mysql.firewall_whitelist表中白名单记录来进行判定(与PROTECTING模式判断规则一样),未匹配到的语句白名单会被记录到错误日志中(被认为是可疑语句),同时状态变量Firewall_access_suspicious+1

  • MySQL企业级防火墙的组成组件:
  • MYSQL_FIREWALL的服务器端插件会在语句执行前根据内存中的缓存内容(information_schema中的白名单缓存表内容)进行检查,根据检查结果来决定是否需要执行还是拒绝某个语句。
  • INFORMATION_SCHEMA中有两张表:MYSQL_FIREWALL_USERS和MYSQL_FIREWALL_WHITELIST,用于提供查看进入到防火墙中的注册用户和白名单规则数据缓存
  • 在mysql数据库中名为firewall_users和firewall_whitelist的系统表提供持久存储防火墙的注册用户和白名单规则数据
  • 名为sp_set_firewall_mode()和sp_reload_firewall_rules()的存储过程用于向防火墙注册MySQL账号以及为用户建立其防火墙模式,以及管理该用户的缓存数据与系统库持久表之间的防火墙数据传输等任务
  • 一组UDF函数,用于提供较低级别的任务,提供SQL级别的API,例如:将缓存数据同步到系统库持久表
  • 用于配置防火墙模式是否启用的系统变量,以及查看防火墙运行状态的状态变量
  • 每个向防火墙注册的帐户都有自己的操作模式。对于在记录模式下的帐户,防火墙会学习应用程序的“指纹”,也就是说,允许访问的语句模式组合在一起形成白名单(在information_schema的缓存表中的白名单记录)。在训练之后,将用户防火墙切换到保护模式,就可以实现强化MySQL,防止与指纹不匹配的语句访问(与白名单中的语句记录不匹配)。如果切换到防护模式之后发现正常的业务SQL被拒绝,则根据需要将用户防火墙切换到记录模式继续进行学习训练,以便生成新语句来更新白名单。检测模式可用于将可疑语句(与白名单不匹配的语句)写入错误日志,但不会拒绝访问
  • 防火墙基于每个帐户的基础上实现各自独立的白名单规则,从而可以实现如下保护策略:

* 对于具有唯一访问保护要求的应用程序,请不要将账号用于其他用途(只用于该应用程序访问)

* 对于一组具有共同访问保护要求的应用程序,请把这些应用程序的访问账号统一为同一个

  • 防火墙操作基于将SQL语句转换为规范化的摘要格式进行。防火墙摘要信息与performance_schema中使用的语句摘要一样。但是,与performance_schema不同的是,这里的摘要信息截取语句的长度只看系统变量max_digest_length的定义值
  • 对于来自在防火墙中的注册帐户的连接,防火墙会将每个传入语句转换为规范化表单并根据帐户模式进行如下处理:

* 在记录模式下,防火墙将规范化语句添加到帐户白名单规则中

* 在防护模式下,防火墙将规范化语句与帐户白名单规则进行比较。如果匹配,则语句通过,服务器继续处理语句。否则,服务器将拒绝该语句并向客户端返回错误信息。如果启用了mysql_firewall_trace系统变量,则防火墙还会将被拒绝的语句写入错误日志中

* 在检测模式下,防火墙会按照保护模式一样的方式匹配语句,但会在不拒绝语句访问的情况下将不匹配的语句写入错误日志中

  • 如果用户未在防火墙中主从过,或者防火墙模式为OFF,则语句直接执行
  • 要使用MySQL企业防火墙进行帐户访问保护,可以按照以下步骤操作:
  • 在防火墙中注册该帐户并将其置于记录模式
  • 使用注册帐户连接到MySQL服务器并执行要学习的语句(正常业务访问的语句)。这个过程会建立帐户的可被防火墙允许访问的语句白名单
  • 将注册帐户切换到防护模式,即可基于语句白名单实现账号的访问保护


  • 使用管理员账号创建需要再防火墙中主从的程序账号,并授予访问权限为数据库应sakila
root@localhost : sakila 07:26:43> CREATE USER 'fwuser'@'localhost' IDENTIFIED BY 'fWp@3sw0rd';
Query OK, 0 rows affected (0.00 sec)

root@localhost : sakila 07:26:51> GRANT ALL on sakila.* TO 'fwuser'@'localhost';
Query OK, 0 rows affected, 1 warning (0.00 sec)
  • 使用sp_set_firewall_mode() 存储过程向防火墙注册帐户并将其置于记录模式(如果该存储过程不在mysql数据库中,则自行修改mysql字符串为其他库名):
root@localhost : sakila 07:27:02> CALL mysql.sp_set_firewall_mode('fwuser@localhost','RECORDING');  # 注意,这里的账号名称需要使用一个引号引起来,用@隔开,跟CREATE USER和grant语句中指定的格式不一样,不要搞混了
+-----------------------------------------------+
| read_firewall_whitelist(arg_userhost,FW.rule) |
+-----------------------------------------------+
| Imported users: 0
Imported rules: 0
          |
+-----------------------------------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)
# 在执行存储过程中,存储过程会调用防火墙的用户定义的函数,这些函数可能会产生自己的输出信息
  • 使用在防火墙中注册的帐户连接到服务器,然后执行一些合法的语句(这里指的是符合账号授予权限的sakila库的访问):
[root@localhost ~]# mysql -ufwuser -pfWp@3sw0rd
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.7.20-enterprise-commercial-advanced-log MySQL Enterprise Server - Advanced Edition (Commercial)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

fwuser@localhost : (none) 07:36:09> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| sakila |
+--------------------+
2 rows in set (0.00 sec)

fwuser@localhost : (none) 07:36:19> use sakila
Database changed
fwuser@localhost : sakila 07:37:22> SELECT first_name,last_name FROM customer WHERE customer_id = 1;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| MARY | SMITH |
+------------+-----------+
1 row in set (0.00 sec)

fwuser@localhost : sakila 07:38:11> UPDATE rental SET return_date = NOW() WHERE rental_id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

fwuser@localhost : sakila 07:38:28> SELECT get_customer_balance(1,NOW());
+-------------------------------+
| get_customer_balance(1,NOW()) |
+-------------------------------+
| 0.00 |
+-------------------------------+
1 row in set (0.00 sec)
# 防火墙会将这些语句转换为摘要表单并将它们记录到帐户白名单中
  • 此时,使用管理员账号可以查询一下白名单记录表中的记录数据
# 可以看到,在Information_schema下的临时缓存表中有白名单语句记录了
root@localhost : sakila 07:39:46> select * from information_schema.MYSQL_FIREWALL_WHITELIST;
+------------------+----------------------------------------------------------------------------+
| USERHOST | RULE |
+------------------+----------------------------------------------------------------------------+
| fwuser@localhost | SELECT `first_name` , `last_name` FROM `customer` WHERE `customer_id` = ? |
| fwuser@localhost | SELECT `get_customer_balance` ( ? , NOW ( ) ) |
| fwuser@localhost | UPDATE `rental` SET `return_date` = NOW ( ) WHERE `rental_id` = ? |
| fwuser@localhost | SELECT SCHEMA ( ) |
| fwuser@localhost | SHOW TABLES |
| fwuser@localhost | DESC `customer` |
| fwuser@localhost | SHOW WARNINGS |
| fwuser@localhost | SELECT `first_name,last_name` FROM `customer` WHERE `customer_id` = ? |
| fwuser@localhost | SELECT @@`version_comment` LIMIT ? |
| fwuser@localhost | SHOW SCHEMAS |
| fwuser@localhost | SELECT SYSTEM_USER ( ) |
+------------------+----------------------------------------------------------------------------+
11 rows in set (0.00 sec)

# 这里可以看到,在记录模式下,mysql系统库下的白名单持久化记录表为空
root@localhost : sakila 07:40:10> select * from mysql.firewall_whitelist;
Empty set (0.00 sec)

# 可以看到,白名单临时表中记录着11行SQL,对应的缓存记录计数器Firewall_cached_entries也增加了11
root@localhost : sakila 07:42:03> show status like '%fire%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Firewall_access_denied | 0 |
| Firewall_access_granted | 0 |
| Firewall_access_suspicious | 0 |
| Firewall_cached_entries | 11 |
+----------------------------+-------+
4 rows in set (0.00 sec)
  • 注意:
  • 要转换到防护模式,必须先要再记录模式下生成语句白名单,否则如果直接切换用户到防护模式,白名单记录为空的话,在防火墙中注册过的用户访问数据库时会因为白名单记录为空而拒绝所有的用户请求
  • 另外,以上查询白名单临时表中的SELECT @@`version_comment` LIMIT ?记录来自于当您以注册用户身份连接到服务器时由mysql客户端自动发送的语句
  • 现在,使用存储过程将注册用户切换到防护模式:
root@localhost : sakila 07:45:34> CALL mysql.sp_set_firewall_mode('fwuser@localhost','PROTECTING');
Query OK, 11 rows affected (0.00 sec)
# 重要:将账户切换到RECORDING模式时会将其防火墙缓存数据同步到mysql系统数据库表中的持久化存储表中。 如果不做做切换防护模式的操作,则mysql系统库中的持久化表会一直为空,且由于Information_schema中的数据是使用的内存临时表,在数据库重启时会丢失。另外如果切换到防护模式时,白名单规则表为空,则存储的过程会返回一个错误信息(但不是SQL级别的错误信息)

# 切换到防护模式之后,查询mysql系统库下的白名单表就有数据了
root@localhost : sakila 07:54:56> select * from mysql.firewall_whitelist;
+------------------+----------------------------------------------------------------------------+
| USERHOST | RULE |
+------------------+----------------------------------------------------------------------------+
| fwuser@localhost | SELECT `first_name` , `last_name` FROM `customer` WHERE `customer_id` = ? |
| fwuser@localhost | SELECT `get_customer_balance` ( ? , NOW ( ) ) |
| fwuser@localhost | UPDATE `rental` SET `return_date` = NOW ( ) WHERE `rental_id` = ? |
| fwuser@localhost | SELECT SCHEMA ( ) |
| fwuser@localhost | SHOW TABLES |
| fwuser@localhost | DESC `customer` |
| fwuser@localhost | SHOW WARNINGS |
| fwuser@localhost | SELECT `first_name,last_name` FROM `customer` WHERE `customer_id` = ? |
| fwuser@localhost | SELECT @@`version_comment` LIMIT ? |
| fwuser@localhost | SHOW SCHEMAS |
| fwuser@localhost | SELECT SYSTEM_USER ( ) |
+------------------+----------------------------------------------------------------------------+
11 rows in set (0.00 sec)
  • 使用注册账户登录数据库,执行一些在白名单中的语句形式和不在白名单中的语句形式,用于测试防火墙的效果,如下
# 下面这句被标准化格式转换之后和白名单表中的SELECT `first_name,last_name` FROM `customer` WHERE `customer_id` = ?相同,所以被允许执行
fwuser@localhost : sakila 07:38:37> SELECT first_name,last_name FROM customer WHERE customer_id ='48';
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| ANN | EVANS |
+------------+-----------+
1 row in set (0.00 sec)

# 下面这些语句被标准化格式转换之后,无法与白名单表中的任何语句匹配,所以全都被拒绝执行
fwuser@localhost : sakila 07:57:22> SELECT first_name,last_name FROM customer WHERE customer_id = 1 OR TRUE;
ERROR 1045 (28000): Statement was blocked by Firewall
fwuser@localhost : sakila 07:58:21> SHOW TABLES LIKE 'customer%';
ERROR 1045 (28000): Statement was blocked by Firewall
Error (Code 1045): Statement was blocked by Firewall
Error (Code 1045): Statement was blocked by Firewall
fwuser@localhost : sakila 07:58:28> TRUNCATE TABLE mysql.slow_log;
ERROR 1045 (28000): Statement was blocked by Firewall
Error (Code 1045): Statement was blocked by Firewall
Error (Code 1045): Statement was blocked by Firewall
Error (Code 1045): Statement was blocked by Firewall
  • 如果启用了mysql_firewall_trace系统变量,防火墙还会将拒绝的语句写入错误日志。类似如下:
[Note] Plugin MYSQL_FIREWALL reported:
'ACCESS DENIED for fwuser@localhost. Reason: No match in whitelist.
Statement: TRUNCATE TABLE `mysql` . `slow_log` '

# 您可以使用这些日志消息来确定攻击者的来源
  • 使用管理语句查询firewall状态变量
root@localhost : sakila 07:55:36> show status like '%fire%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Firewall_access_denied | 3 |  # 可以发现被拒绝的次数为3
| Firewall_access_granted | 4 |  # 可以发现被允许的次数为4,这里计数器计算了3次拒绝SQL中附带的客户端发送的select @@version_comment,所以看起来像是被拒绝的语句也被同时计算了
| Firewall_access_suspicious | 0 |
| Firewall_cached_entries | 11 |
+----------------------------+-------+
4 rows in set (0.00 sec)
  • 如果不希望拒绝不被允许的语句执行,而是进行记录,以备审计查询,则,可以修改用户的防火墙模式为检测模式,如下
root@localhost : sakila 08:02:29> CALL mysql.sp_set_firewall_mode('fwuser@localhost','DETECTING');
Query OK, 11 rows affected (0.00 sec)
  • 使用注册帐户连接到服务器,然后执行与白名单不匹配的语句:
fwuser@localhost : sakila 08:02:15> SHOW TABLES LIKE 'customer%';
Empty set (0.00 sec)

# 在检测模式下,防火墙允许执行与白名单不匹配的语句,但会将消息写入错误日志中
2018-06-26T20:07:30.160511+08:00 12 [Note] Plugin MYSQL_FIREWALL reported: 'SUSPICIOUS STATEMENT from 'fwuser@localhost'. Reason: No match in whitelist. Statement: SHOW TABLES LIKE ? '
  • 使用管理账号登录数据库,查看firewall状态变量
root@localhost : sakila 08:09:38> SHOW GLOBAL STATUS LIKE '%fire%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Firewall_access_denied | 4 |
| Firewall_access_granted | 6 |
| Firewall_access_suspicious | 1 |  # 可以发现,在检测模式下,检测到一次可疑的SQL语句
| Firewall_cached_entries | 11 |
+----------------------------+-------+
4 rows in set (0.01 sec)
  • 如果发现业务正常访问的SQL不在白名单中,则你需要修改用户的防火墙模式为记录模式,更新白名单语句,然后再切换到防护模式或者检测模式即可

  • 用户自定义变量使用示例

  • 如果要清空计数器状态变量,可以使用如下自定义函数
root@localhost : sakila 08:56:48> SELECT mysql_firewall_flush_status();
+-------------------------------+
| mysql_firewall_flush_status() |
+-------------------------------+
| OK
                           |
+-------------------------------+
1 row in set (0.00 sec)

root@localhost : sakila 08:57:35> SHOW GLOBAL STATUS LIKE '%fire%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Firewall_access_denied | 0 |
| Firewall_access_granted | 0 |
| Firewall_access_suspicious | 0 |
| Firewall_cached_entries | 11 |  # 该函数不会清空该状态变量值
+----------------------------+-------+
4 rows in set (0.00 sec)
  • 如果要切换用户的防火墙模式,可以使用如下存储过程
# 该存储过程在前面的示例中已经介绍过了,这里不再赘述
mysql.sp_set_firewall_mode(user,mode); # mode有效值详见firewall_users表的MODE字段含义介绍
  • 如果需要重置用户的访问模式,可以使用如下存储过程(只重置Information_schema中的临时注册用户记录表,其他表中的数据不会改变)
root@localhost : (none) 10:31:57> CALL mysql.sp_reload_firewall_rules('fwuser@localhost');
+--------+
| Result |
+--------+
| OK |
+--------+
1 row in set (0.00 sec)

+---------------------------------------+
| Result |
+---------------------------------------+
| Imported users: 0
Imported rules: 11
 |
+---------------------------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

root@localhost : (none) 10:32:11> select * from information_schema.mysql_firewall_users;
+------------------+------+
| USERHOST | MODE |
+------------------+------+
| fwuser@localhost | OFF |
+------------------+------+
1 row in set (0.00 sec)
  • 如果需要手动在白名单记录表中插入语句,可以使用如下自定义函数(给定的原始语句会被标准化格式转换之后出入白名单表中)
# 实测不生效,报需要SUPER_ACL 权限(管理员调用函数可以成功,但是并没有添加白名单语句到表中)
fwuser@localhost : sakila 10:45:47> SELECT normalize_statement('SELECT * FROM actor WHERE actor_id > 2');
+---------------------------------------------------------------------------------------------+
| normalize_statement('SELECT * FROM actor WHERE actor_id > 2') |
+---------------------------------------------------------------------------------------------+
| ERROR: Request ignored for user 'fwuser'@'localhost'. SUPER_ACL needed to perform operation |
+---------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
  • 读取mysql系统库下的持久表mysql.firewall_users中的给定用户防火墙模式更新到information_schema.mysql_firewall_users表中
# 执行sp_reload_firewall_rules存储过程
root@localhost : (none) 10:46:04> CALL mysql.sp_reload_firewall_rules('fwuser@localhost');
+--------+
| Result |
+--------+
| OK |
+--------+
1 row in set (0.00 sec)

+---------------------------------------+
| Result |
+---------------------------------------+
| Imported users: 0
Imported rules: 11
 |
+---------------------------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

# 查询临时用户注册表,发现访问模式被设置为OFF
root@localhost : (none) 10:50:08> select * from information_schema.mysql_firewall_users;
+------------------+------+
| USERHOST | MODE |
+------------------+------+
| fwuser@localhost | OFF |
+------------------+------+
1 row in set (0.00 sec)

# 查看持久化用户注册表,发现并没有改变
root@localhost : (none) 10:49:13> select * from mysql.firewall_users;
+------------------+-----------+
| USERHOST | MODE |
+------------------+-----------+
| fwuser@localhost | RECORDING |
+------------------+-----------+
1 row in set (0.00 sec)

# 使用read_firewall_users函数从mysql系统库下的持久表读取给定用户的访问模式更新到Information_schema表下的临时用户注册表中
root@localhost : (none) 10:50:14> SELECT read_firewall_users('fwuser@localhost', 'RECORDING')
    -> FROM mysql.firewall_users;
+------------------------------------------------------+
| read_firewall_users('fwuser@localhost', 'RECORDING') |
+------------------------------------------------------+
| Imported users: 0
Updated users: 1
                 |
+------------------------------------------------------+
1 row in set (0.00 sec)

# 查看更新结果,发现临时用户注册表中的给定用户访问模式记录被更新为RECORDING模式
root@localhost : (none) 10:50:17> select * from information_schema.mysql_firewall_users;
+------------------+-----------+
| USERHOST | MODE |
+------------------+-----------+
| fwuser@localhost | RECORDING |
+------------------+-----------+
1 row in set (0.00 sec)
  • 如果想要从持久表中读取给定用户的白名单语句覆盖掉information_schema下临时表的白名单规则,可以使用如下自定义函数
root@localhost : (none) 11:00:17> SELECT read_firewall_whitelist('fwuser@localhost','RECORDING') FROM mysql.firewall_whitelist;
+---------------------------------------------------------+
| read_firewall_whitelist('fwuser@localhost','RECORDING') |
+---------------------------------------------------------+
| Imported users: 0
Imported rules: 1
                    |
+---------------------------------------------------------+
1 row in set (0.00 sec)
  • 如果想要只修改Information_schema下的临时内存用户注册表中的访问模式,可以使用如下自定义函数
root@localhost : (none) 11:04:06> SELECT set_firewall_mode('fwuser@localhost', 'PROTECTING');
+-----------------------------------------------------+
| set_firewall_mode('fwuser@localhost', 'PROTECTING') |
+-----------------------------------------------------+
| OK |
+-----------------------------------------------------+
1 row in set (0.00 sec)

# 持久表中还是RECORDING模式
root@localhost : (none) 11:05:38> select * from mysql.firewall_users;
+------------------+-----------+
| USERHOST | MODE |
+------------------+-----------+
| fwuser@localhost | RECORDING |
+------------------+-----------+
1 row in set (0.00 sec)

# 临时表中已经被修改为PROTECTING模式
root@localhost : (none) 11:05:42> select * from information_schema.mysql_firewall_users;
+------------------+------------+
| USERHOST | MODE |
+------------------+------------+
| fwuser@localhost | PROTECTING |
+------------------+------------+
1 row in set (0.00 sec)
  • 参考链接:

上一篇:audit_log_user表 |下一篇:firewall_users表

⚠️ **GitHub.com Fallback** ⚠️