Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 Reference Manual  /  ...  /  SQL-Based Account Activity Auditing

8.2.23 基于 SQL 的帐户活动审计

应用程序可以使用以下指导原则来执行基于 SQL 的帐户活动审计,以将数据库活动与 MySQL 帐户相关联。

MySQL 帐户对应于 mysql.user 系统表中的行。当客户端成功连接时,服务器将客户端验证到该表中的一行。该行的 UserHost 列值唯一标识帐户,并对应于 SQL 语句中帐户名称的格式,即 'user_name'@'host_name'。

用于验证客户端的帐户确定了客户端拥有的权限。通常,可以调用 CURRENT_USER() 函数以确定客户端用户的帐户。这函数的值是从 user 表中帐户行的 UserHost 列值构建而来的。

然而,在某些情况下,CURRENT_USER() 函数的值不对应于客户端用户,而是对应于不同的帐户。这发生在权限检查不是基于客户端帐户时:

  • 存储程序(过程和函数)定义了具有 SQL SECURITY DEFINER 特性

  • 视图定义了具有 SQL SECURITY DEFINER 特性

  • 触发器和事件

在这些上下文中,权限检查是基于定义者帐户的,而 CURRENT_USER() 引用的是该帐户,而不是客户端用户。要确定调用用户,可以调用 USER() 函数,这个函数返回一个值,表示客户端提供的实际用户名和来自客户端连接的主机名。但是,这个值不一定对应于 user 表中的帐户,因为 USER() 函数的值从不包含通配符,而帐户值(如由 CURRENT_USER() 函数返回)可能包含用户名和主机名通配符。

例如,如果客户端从本地主机连接为 user1,那么 USER()CURRENT_USER() 返回不同的值:

mysql> SELECT USER(), CURRENT_USER();
+-----------------+----------------+
| USER()           | CURRENT_USER()  |
+-----------------+----------------+
| user1@localhost  | @localhost      |
+-----------------+----------------+

主机名部分的一个帐户也可以包含通配符。如果主机名包含一个'%''_'模式字符或使用netmask notation,帐户可以用于来自多个主机的客户端,并且CURRENT_USER()值不表示哪一个。例如,帐户'user2'@'%.example.com'可以由user2用于从任何主机连接到example.com域。如果user2remote.example.com连接,USER()CURRENT_USER()返回不同的值:

mysql> SELECT USER(), CURRENT_USER();
+--------------------------+---------------------+
| USER()                    | CURRENT_USER()       |
+--------------------------+---------------------+
| user2@remote.example.com  | user2@%.example.com  |
+--------------------------+---------------------+

如果应用程序必须在触发器中调用USER()进行用户审核(例如,如果它从within triggers做审核),但同时也需要将USER()值与帐户在user表中关联,则必须避免包含通配符的帐户在UserHost列中。具体来说,不要允许User为空(这创建了匿名用户帐户),也不要允许模式字符或netmask notation在Host值中。所有帐户都必须有一个非空的User值和字面Host值。

关于前面的示例,'''@'localhost''user2'@'%.example.com'帐户应该被更改以不使用通配符:

RENAME USER ''@'localhost' TO 'user1'@'localhost';
RENAME USER 'user2'@'%.example.com' TO 'user2'@'remote.example.com';

如果user2必须从多个主机在example.com域中连接,那么应该为每个主机创建一个单独的帐户。

要提取用户名称或主机名部分CURRENT_USER()USER()值,可以使用SUBSTRING_INDEX()函数:

mysql> SELECT SUBSTRING_INDEX(CURRENT_USER(),'@',1);
+---------------------------------------+
| SUBSTRING_INDEX(CURRENT_USER(),'@',1)  |
+---------------------------------------+
| user1                                  |
+---------------------------------------+

mysql> SELECT SUBSTRING_INDEX(CURRENT_USER(),'@',-1);
+----------------------------------------+
| SUBSTRING_INDEX(CURRENT_USER(),'@',-1)  |
+----------------------------------------+
| localhost                               |
+----------------------------------------+