文档主页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
手册页 (TGZ) - 258.5Kb
手册页 (Zip) - 365.5Kb
信息 (Gzip) - 4.0Mb
信息 (Zip) - 4.0Mb


MySQL 8.4 参考手册  /  ...  /  基于 SQL 的帐户活动审计

8.2.23 基于 SQL 的帐户活动审计

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

MySQL 帐户对应于 mysql.user 系统表中的行。当客户端连接成功时,服务器会对该表中特定行的客户端进行身份验证。UserHost 列中的值唯一标识帐户,并对应于 SQL 语句中写入帐户名的 '用户名'@'主机名' 格式。

用于对客户端进行身份验证的帐户决定了客户端拥有的权限。通常,可以调用 CURRENT_USER() 函数来确定客户端用户的帐户。其值由帐户的 user 表行的 UserHost 列构成。

但是,在某些情况下,CURRENT_USER() 值对应的不是客户端用户,而是其他帐户。当权限检查不是基于客户端的帐户时,就会出现这种情况。

  • 使用 SQL SECURITY DEFINER 特性定义的存储例程(过程和函数)

  • 使用 SQL SECURITY DEFINER 特性定义的视图

  • 触发器和事件

在这些上下文中,权限检查是针对 DEFINER 帐户执行的,并且 CURRENT_USER() 指的是该帐户,而不是调用存储例程或视图或导致触发器激活的客户端的帐户。要确定调用用户,可以调用 USER() 函数,该函数返回一个值,该值指示客户端提供的实际用户名以及客户端连接的主机。但是,此值不一定直接对应于 user 表中的帐户,因为 USER() 值从不包含通配符,而帐户值(由 CURRENT_USER() 返回)可能包含用户名和主机名通配符。

例如,空白用户名匹配任何用户,因此 ''@'localhost' 帐户允许客户端以任何用户名从本地主机匿名连接。在这种情况下,如果客户端以 user1 身份从本地主机连接,则 USER()CURRENT_USER() 将返回不同的值。

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

帐户的主机名部分也可以包含通配符。如果主机名包含 '%''_' 模式字符或使用网络掩码表示法,则该帐户可用于从多个主机连接的客户端,并且 CURRENT_USER() 值不会指示是哪个主机。例如,'user2'@'%.example.com' 帐户可由 user2 用于从 example.com 域中的任何主机连接。如果 user2remote.example.com 连接,则 USER()CURRENT_USER() 将返回不同的值。

mysql> SELECT USER(), CURRENT_USER();
+--------------------------+---------------------+
| USER()                   | CURRENT_USER()      |
+--------------------------+---------------------+
| [email protected] | user2@%.example.com |
+--------------------------+---------------------+

如果应用程序必须调用 USER() 函数进行用户审计(例如,如果它从触发器内部进行审计),但也必须能够将 USER() 值与 user 表中的帐户相关联,则必须避免在 UserHost 列中包含通配符的帐户。具体来说,不允许 User 为空(这将创建一个匿名用户帐户),并且不允许在 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                              |
+----------------------------------------+