本节介绍如何编写服务器端审计插件,使用 MySQL 源代码发行版中 plugin/audit_null
目录中的示例插件。该目录中的 audit_null.c
和 audit_null_variables.h
源文件实现了名为 NULL_AUDIT
的审计插件。
在服务器中,可插拔审计接口在 MySQL 源代码发行版中 sql
目录中的 sql_audit.h
和 sql_audit.cc
文件中实现。此外,服务器中的多个地方在发生可审计事件时会调用审计接口,以便在必要时通知已注册的审计插件有关该事件。要查看此类调用发生的位置,请搜索服务器源文件,以查找调用名称类似于 mysql_audit_
的函数的调用。审计通知发生在以下服务器操作中:xxx
()
客户端连接和断开连接事件
向通用查询日志写入消息(如果启用了日志)
向错误日志写入消息
将查询结果发送到客户端
要编写审计插件,请在插件源文件中包含以下头文件。根据插件的功能和要求,可能还需要其他 MySQL 或通用头文件。
#include <mysql/plugin_audit.h>
plugin_audit.h
包含 plugin.h
,因此您无需显式包含后者文件。 plugin.h
定义了 MYSQL_AUDIT_PLUGIN
服务器插件类型以及声明插件所需的数据结构。 plugin_audit.h
定义了特定于审计插件的数据结构。
审计插件,像任何 MySQL 服务器插件一样,都有一个通用插件描述符(请参见 第 4.4.2.1 节,“服务器插件库和插件描述符”)和一个类型特定插件描述符。在 audit_null.c
中,audit_null
的通用描述符如下所示
mysql_declare_plugin(audit_null)
{
MYSQL_AUDIT_PLUGIN, /* type */
&audit_null_descriptor, /* descriptor */
"NULL_AUDIT", /* name */
"Oracle Corporation", /* author */
"Simple NULL Audit", /* description */
PLUGIN_LICENSE_GPL,
audit_null_plugin_init, /* init function (when loaded) */
audit_null_plugin_deinit, /* deinit function (when unloaded) */
0x0003, /* version */
simple_status, /* status variables */
system_variables, /* system variables */
NULL,
0,
}
mysql_declare_plugin_end;
第一个成员 MYSQL_AUDIT_PLUGIN
将此插件标识为审计插件。
audit_null_descriptor
指向类型特定插件描述符,将在后面介绍。
成员 name
(NULL_AUDIT
) 指示在语句(如 INSTALL PLUGIN
或 UNINSTALL PLUGIN
)中引用插件时要使用的名称。这也是 INFORMATION_SCHEMA.PLUGINS
或 SHOW PLUGINS
显示的名称。
初始化函数 audit_null_plugin_init
在加载插件时执行插件初始化。函数 audit_null_plugin_deinit
在卸载插件时执行清理。
通用插件描述符还引用了 simple_status
和 system_variables
,这些结构公开了多个状态和系统变量。启用插件后,可以使用 SHOW
语句(SHOW STATUS
、SHOW VARIABLES
)或相应的 Performance Schema 表检查这些变量。
结构 simple_status
声明了多个状态变量,其名称格式为 Audit_null_
。 xxx
NULL_AUDIT
为它收到的每个通知都增加状态变量 Audit_null_called
。其他状态变量更具体,NULL_AUDIT
仅为特定事件的通知增加这些变量。
system_variables
是一个系统变量元素数组,每个元素都使用 MYSQL_THDVAR_
宏定义。这些系统变量的名称格式为 xxx
null_audit_
。这些变量可用于在运行时与插件通信。xxx
通用插件描述符中的值 audit_null_descriptor
指向类型特定插件描述符。对于审计插件,此描述符具有以下结构(在 plugin_audit.h
中定义)
struct st_mysql_audit
{
int interface_version;
void (*release_thd)(MYSQL_THD);
int (*event_notify)(MYSQL_THD, mysql_event_class_t, const void *);
unsigned long class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
};
审计插件的类型特定描述符具有以下成员
interface_version
:按照惯例,类型特定插件描述符从给定插件类型的接口版本开始。服务器在加载插件时检查interface_version
,以查看插件是否与其兼容。对于审计插件,成员interface_version
的值为MYSQL_AUDIT_INTERFACE_VERSION
(在plugin_audit.h
中定义)。release_thd
:服务器用来通知插件它已从其线程上下文分离的函数。如果不存在此类函数,则应为NULL
。event_notify
:服务器用来通知插件已发生可审计事件的函数。此函数不应为NULL
;因为那样将毫无意义,因为不会发生任何审计。class_mask
:一个包含MYSQL_AUDIT_CLASS_MASK_SIZE
个元素的数组。每个元素指定给定事件类的位掩码,以指示插件希望接收通知的子类。(这就是插件 “订阅” 感兴趣的事件的方式。)元素应为 0,以忽略对应事件类的所有事件。
服务器将函数 event_notify
和 release_thd
结合使用。它们在特定线程的上下文中调用,并且线程可能执行导致多个事件通知的活动。服务器第一次为线程调用 event_notify
时,它会创建插件与线程的绑定。在创建此绑定之前,不能卸载插件。当线程不再发生事件时,服务器会通过调用函数 release_thd
通知插件,然后销毁绑定。例如,当客户端发出语句时,处理该语句的线程可能会通知审计插件有关该语句产生的结果集以及该语句是否已记录。在这些通知发生后,服务器会在将线程置于休眠状态以等待客户端发出另一个语句之前,释放插件。
这种设计使插件能够在第一次调用 event_notify
函数时分配给定线程所需的资源,并在 release_thd
函数中释放这些资源
event_notify function:
if memory is needed to service the thread
allocate memory
... rest of notification processing ...
release_thd function:
if memory was allocated
release memory
... rest of release processing ...
与在通知函数中重复分配和释放内存相比,这种方法效率更高。
对于 NULL_AUDIT
审计插件,类型特定插件描述符如下所示
static struct st_mysql_audit audit_null_descriptor=
{
MYSQL_AUDIT_INTERFACE_VERSION, /* interface version */
NULL, /* release_thd function */
audit_null_notify, /* notify function */
{ (unsigned long) MYSQL_AUDIT_GENERAL_ALL,
(unsigned long) MYSQL_AUDIT_CONNECTION_ALL,
(unsigned long) MYSQL_AUDIT_PARSE_ALL,
(unsigned long) MYSQL_AUDIT_AUTHORIZATION_ALL,
(unsigned long) MYSQL_AUDIT_TABLE_ACCESS_ALL,
(unsigned long) MYSQL_AUDIT_GLOBAL_VARIABLE_ALL,
(unsigned long) MYSQL_AUDIT_SERVER_STARTUP_ALL,
(unsigned long) MYSQL_AUDIT_SERVER_SHUTDOWN_ALL,
(unsigned long) MYSQL_AUDIT_COMMAND_ALL,
(unsigned long) MYSQL_AUDIT_QUERY_ALL,
(unsigned long) MYSQL_AUDIT_STORED_PROGRAM_ALL }
};
服务器调用 audit_null_notify()
将审计事件信息传递给插件。插件没有 release_thd
函数。
成员 class_mask
是一个数组,指示插件订阅哪些事件类。如所示,数组内容订阅了所有可用的事件类的所有子类。要忽略给定事件类的所有通知,请将相应的 class_mask
元素指定为 0。
class_mask
元素的数量对应于事件类的数量,每个事件类都列在 plugin_audit.h
中定义的 mysql_event_class_t
枚举中
typedef enum
{
MYSQL_AUDIT_GENERAL_CLASS = 0,
MYSQL_AUDIT_CONNECTION_CLASS = 1,
MYSQL_AUDIT_PARSE_CLASS = 2,
MYSQL_AUDIT_AUTHORIZATION_CLASS = 3,
MYSQL_AUDIT_TABLE_ACCESS_CLASS = 4,
MYSQL_AUDIT_GLOBAL_VARIABLE_CLASS = 5,
MYSQL_AUDIT_SERVER_STARTUP_CLASS = 6,
MYSQL_AUDIT_SERVER_SHUTDOWN_CLASS = 7,
MYSQL_AUDIT_COMMAND_CLASS = 8,
MYSQL_AUDIT_QUERY_CLASS = 9,
MYSQL_AUDIT_STORED_PROGRAM_CLASS = 10,
/* This item must be last in the list. */
MYSQL_AUDIT_CLASS_MASK_SIZE
} mysql_event_class_t;
对于任何给定的事件类,plugin_audit.h
都定义了单个事件子类的位掩码符号,以及一个
符号,它是所有子类位掩码的并集。例如,对于 xxx
_ALLMYSQL_AUDIT_CONNECTION_CLASS
(涵盖连接和断开连接事件的类),plugin_audit.h
定义了以下符号
typedef enum
{
/** occurs after authentication phase is completed. */
MYSQL_AUDIT_CONNECTION_CONNECT = 1 << 0,
/** occurs after connection is terminated. */
MYSQL_AUDIT_CONNECTION_DISCONNECT = 1 << 1,
/** occurs after COM_CHANGE_USER RPC is completed. */
MYSQL_AUDIT_CONNECTION_CHANGE_USER = 1 << 2,
/** occurs before authentication. */
MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE = 1 << 3
} mysql_event_connection_subclass_t;
#define MYSQL_AUDIT_CONNECTION_ALL (MYSQL_AUDIT_CONNECTION_CONNECT | \
MYSQL_AUDIT_CONNECTION_DISCONNECT | \
MYSQL_AUDIT_CONNECTION_CHANGE_USER | \
MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE)
要订阅连接事件类的所有子类(如 NULL_AUDIT
插件所做的那样),插件会在相应的 class_mask
元素中指定 MYSQL_AUDIT_CONNECTION_ALL
(在本例中为 class_mask[1]
)。要仅订阅某些子类,插件会将 class_mask
元素设置为感兴趣的子类的并集。例如,要仅订阅连接和更改用户子类,插件会将 class_mask[1]
设置为以下值
MYSQL_AUDIT_CONNECTION_CONNECT | MYSQL_AUDIT_CONNECTION_CHANGE_USER
审计插件的大部分工作都在通知函数(类型特定插件描述符的 event_notify
成员)中完成。服务器会为每个可审计事件调用此函数。审计插件通知函数具有以下原型
int (*event_notify)(MYSQL_THD, mysql_event_class_t, const void *);
event_notify
函数原型中的第二个和第三个参数分别代表事件类和指向事件结构的通用指针。(不同类别的事件具有不同的结构。通知函数可以使用事件类值来确定适用哪个事件结构。)该函数处理事件并返回一个状态,指示服务器应该继续处理事件还是终止它。
对于 NULL_AUDIT
,通知函数为 audit_null_notify()
。此函数会递增一个全局事件计数器(插件将其公开为 Audit_null_called
状态值的的值),然后检查事件类以确定如何处理事件结构。
static int audit_null_notify(MYSQL_THD thd __attribute__((unused)),
mysql_event_class_t event_class,
const void *event)
{
...
number_of_calls++;
if (event_class == MYSQL_AUDIT_GENERAL_CLASS)
{
const struct mysql_event_general *event_general=
(const struct mysql_event_general *)event;
...
}
else if (event_class == MYSQL_AUDIT_CONNECTION_CLASS)
{
const struct mysql_event_connection *event_connection=
(const struct mysql_event_connection *) event;
...
}
else if (event_class == MYSQL_AUDIT_PARSE_CLASS)
{
const struct mysql_event_parse *event_parse =
(const struct mysql_event_parse *)event;
...
}
...
}
通知函数根据 event_class
的值来解释 event
参数。 event
参数是指向事件记录的通用指针,其结构因事件类而异。(plugin_audit.h
文件包含定义每个事件类内容的结构。)对于每个类, audit_null_notify()
将事件强制转换为相应的类特定结构,然后检查其子类以确定要递增哪个子类计数器。例如,处理连接事件类中事件的代码如下所示
else if (event_class == MYSQL_AUDIT_CONNECTION_CLASS)
{
const struct mysql_event_connection *event_connection=
(const struct mysql_event_connection *) event;
switch (event_connection->event_subclass)
{
case MYSQL_AUDIT_CONNECTION_CONNECT:
number_of_calls_connection_connect++;
break;
case MYSQL_AUDIT_CONNECTION_DISCONNECT:
number_of_calls_connection_disconnect++;
break;
case MYSQL_AUDIT_CONNECTION_CHANGE_USER:
number_of_calls_connection_change_user++;
break;
case MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE:
number_of_calls_connection_pre_authenticate++;
break;
default:
break;
}
}
通用事件类 (MYSQL_AUDIT_GENERAL_CLASS
) 已被弃用,将在未来的 MySQL 版本中删除。为了减少插件开销,最好只订阅感兴趣的更具体的事件类。
对于某些事件类, NULL_AUDIT
插件除了递增计数器之外还会执行其他处理。无论如何,当通知函数完成事件处理后,它应该返回一个状态,指示服务器应该继续处理事件还是终止它。
审核插件通知函数可以通过两种方式报告当前事件的状态值
使用通知函数返回值。在这种情况下,如果服务器应该继续处理事件,函数返回零,如果服务器应该终止事件,则返回非零值。
-
调用
my_message()
函数以在从通知函数返回之前设置错误状态。在这种情况下,通知函数返回值将被忽略,服务器会中止事件并使用错误终止事件处理。my_message()
参数指示要报告哪个错误以及其消息。例如my_message(ER_AUDIT_API_ABORT, "This is my error message.", MYF(0));
某些事件无法中止。非零返回值不会被考虑,并且
my_message()
错误调用必须在is_error()
检查之后进行。例如if (!thd->get_stmt_da()->is_error()) { my_message(ER_AUDIT_API_ABORT, "This is my error message.", MYF(0)); }
这些事件无法中止
MYSQL_AUDIT_CONNECTION_DISCONNECT
:服务器无法阻止客户端断开连接。MYSQL_AUDIT_COMMAND_END
:此事件提供了已完成执行的命令的状态,因此终止它没有意义。
如果审核插件为不可终止事件返回非零状态,则服务器会忽略该状态并继续处理事件。如果审核插件使用 my_message()
函数终止不可终止事件,也是如此。
要编译和安装插件库文件,请使用 第 4.4.3 节,“编译和安装插件库” 中的说明。要使库文件可供使用,请将其安装在插件目录中(由 plugin_dir
系统变量命名的目录)。对于 NULL_AUDIT
插件,在从源代码构建 MySQL 时,它会被编译和安装。它也包含在二进制发行版中。构建过程会生成一个名为 adt_null.so
的共享对象库(.so
后缀可能因平台而异)。
要在运行时注册插件,请使用以下语句,根据需要调整您的平台的 .so
后缀
INSTALL PLUGIN NULL_AUDIT SONAME 'adt_null.so';
有关插件加载的更多信息,请参阅 安装和卸载插件。
要验证插件安装,请检查 INFORMATION_SCHEMA.PLUGINS
表或使用 SHOW PLUGINS
语句。请参阅 获取服务器插件信息。
在安装 NULL_AUDIT
审核插件时,它会公开状态变量,指示插件已被调用的事件
mysql> SHOW STATUS LIKE 'Audit_null%';
+----------------------------------------+--------+
| Variable_name | Value |
+----------------------------------------+--------+
| Audit_null_authorization_column | 0 |
| Audit_null_authorization_db | 0 |
| Audit_null_authorization_procedure | 0 |
| Audit_null_authorization_proxy | 0 |
| Audit_null_authorization_table | 0 |
| Audit_null_authorization_user | 0 |
| Audit_null_called | 185547 |
| Audit_null_command_end | 20999 |
| Audit_null_command_start | 21001 |
| Audit_null_connection_change_user | 0 |
| Audit_null_connection_connect | 5823 |
| Audit_null_connection_disconnect | 5818 |
| Audit_null_connection_pre_authenticate | 5823 |
| Audit_null_general_error | 1 |
| Audit_null_general_log | 26559 |
| Audit_null_general_result | 19922 |
| Audit_null_general_status | 21000 |
| Audit_null_global_variable_get | 0 |
| Audit_null_global_variable_set | 0 |
| Audit_null_message_internal | 0 |
| Audit_null_message_user | 0 |
| Audit_null_parse_postparse | 14648 |
| Audit_null_parse_preparse | 14648 |
| Audit_null_query_nested_start | 6 |
| Audit_null_query_nested_status_end | 6 |
| Audit_null_query_start | 14648 |
| Audit_null_query_status_end | 14647 |
| Audit_null_server_shutdown | 0 |
| Audit_null_server_startup | 1 |
| Audit_null_table_access_delete | 104 |
| Audit_null_table_access_insert | 2839 |
| Audit_null_table_access_read | 97842 |
| Audit_null_table_access_update | 278 |
+----------------------------------------+--------+
Audit_null_called
统计所有事件,其他变量统计特定事件子类的实例。例如,前面的 SHOW STATUS
语句会导致服务器将结果发送到客户端并将消息写入通用查询日志(如果该日志已启用)。因此,重复发出该语句的客户端会导致 Audit_null_called
、Audit_null_general_result
和 Audit_null_general_log
在每次执行时都递增。无论该日志是否已启用,都会发生通知。
状态变量值是全局的,并在所有会话中进行聚合。没有针对单个会话的计数器。
NULL_AUDIT
公开了几个系统变量,这些变量使能够在运行时与插件进行通信
mysql> SHOW VARIABLES LIKE 'null_audit%';
+---------------------------------------------------+-------+
| Variable_name | Value |
+---------------------------------------------------+-------+
| null_audit_abort_message | |
| null_audit_abort_value | 1 |
| null_audit_event_order_check | |
| null_audit_event_order_check_consume_ignore_count | 0 |
| null_audit_event_order_check_exact | 1 |
| null_audit_event_order_started | 0 |
| null_audit_event_record | |
| null_audit_event_record_def | |
+---------------------------------------------------+-------+
NULL_AUDIT
系统变量具有以下含义
null_audit_abort_message
:中止事件时要使用的自定义错误消息。null_audit_abort_value
:中止事件时要使用的自定义错误代码。null_audit_event_order_check
:在事件匹配之前,预期事件顺序。在事件匹配之后,匹配结果。null_audit_event_order_check_consume_ignore_count
:事件匹配不应该使用匹配事件的次数。null_audit_event_order_check_exact
:事件匹配是否必须完全匹配。禁用此变量允许在事件顺序匹配期间跳过null_audit_event_order_check
中未列出的事件。在指定的事件中,它们必须按给定顺序匹配。null_audit_event_order_started
:供内部使用。null_audit_event_record
:事件记录发生后记录的事件。null_audit_event_record_def
:用于在记录事件时匹配的开始和结束事件的名称,以分号分隔。该值必须在记录事件的每个语句之前设置。
为了演示这些系统变量的使用,假设存在一个名为 db1.t1
的表,创建如下所示
CREATE DATABASE db1;
CREATE TABLE db1.t1 (a VARCHAR(255));
为了测试创建,可以记录通过插件的事件。要开始记录,请在 null_audit_event_record_def
变量中指定开始和结束事件。例如
SET @@null_audit_event_record_def =
'MYSQL_AUDIT_COMMAND_START;MYSQL_AUDIT_COMMAND_END';
在发生与这些开始和结束事件匹配的语句后, null_audit_event_record
系统变量将包含生成的事件序列。例如,在记录 SELECT 1
语句的事件后, null_audit_event_record
是一个字符串,其值为一组事件字符串
MYSQL_AUDIT_COMMAND_START;command_id="3";
MYSQL_AUDIT_PARSE_PREPARSE;;
MYSQL_AUDIT_PARSE_POSTPARSE;;
MYSQL_AUDIT_GENERAL_LOG;;
MYSQL_AUDIT_QUERY_START;sql_command_id="0";
MYSQL_AUDIT_QUERY_STATUS_END;sql_command_id="0";
MYSQL_AUDIT_GENERAL_RESULT;;
MYSQL_AUDIT_GENERAL_STATUS;;
MYSQL_AUDIT_COMMAND_END;command_id="3";
在记录 INSERT INTO db1.t1 VALUES ('some data')
语句的事件后, null_audit_event_record
将具有以下值
MYSQL_AUDIT_COMMAND_START;command_id="3";
MYSQL_AUDIT_PARSE_PREPARSE;;
MYSQL_AUDIT_PARSE_POSTPARSE;;
MYSQL_AUDIT_GENERAL_LOG;;
MYSQL_AUDIT_QUERY_START;sql_command_id="5";
MYSQL_AUDIT_TABLE_ACCESS_INSERT;db="db1" table="t1";
MYSQL_AUDIT_QUERY_STATUS_END;sql_command_id="5";
MYSQL_AUDIT_GENERAL_RESULT;;
MYSQL_AUDIT_GENERAL_STATUS;;
MYSQL_AUDIT_COMMAND_END;command_id="3";
每个事件字符串都具有以下格式,以分号分隔字符串部分
event_name;event_data;command
事件字符串具有以下部分
event_name
:事件名称(以MYSQL_AUDIT_
开头的符号)。event_data
:空,或者,如后文所述,与事件相关联的数据。command
:空,或者,如后文所述,在匹配事件时要执行的命令。
NULL_AUDIT
插件的一个限制是,事件记录只针对单个会话有效。一旦在给定会话中记录了事件,后续会话中的事件记录将产生一个值为 NULL
的 null_audit_event_record
值。要再次记录事件,必须重新启动插件。
要检查审核 API 调用的顺序,请将 null_audit_event_order_check
变量设置为特定操作的预期事件顺序,列出一条或多条事件字符串,每条事件字符串在内部包含两个分号,并在相邻事件字符串之间用额外的分号分隔
event_name;event_data;command [;event_name;event_data;command] ...
例如
SET @@null_audit_event_order_check =
'MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE;;;'
'MYSQL_AUDIT_GENERAL_LOG;;;'
'MYSQL_AUDIT_CONNECTION_CONNECT;;';
为了更好地可读性,该语句利用了 SQL 语法,该语法将相邻字符串连接成一个字符串。
在将 null_audit_event_order_check
变量分配给要匹配的事件列表后,下一个匹配操作将用指示操作结果的值替换变量值
如果成功匹配预期事件顺序,则生成的
null_audit_event_order_check
值为EVENT-ORDER-OK
。如果指定的
null_audit_event_order_check
值中止匹配事件(如后文所述),则生成的null_audit_event_order_check
值为EVENT-ORDER-ABORT
。如果预期事件顺序因意外数据而失败,则生成的
null_audit_event_order_check
值为EVENT-ORDER-INVALID-DATA
。例如,如果指定事件预计会影响表t1
,但实际上影响了t2
,就会发生这种情况。
在将事件列表分配给 null_audit_event_order_check
时,某些事件应在事件字符串的 event_data
部分中指定一个非空值。下表显示了这些事件的 event_data
格式。如果事件使用多个数据值,则必须按所示顺序指定它们。或者,可以将 event_data
值指定为 <IGNORE>
以忽略事件数据内容;在这种情况下,事件是否有数据并不重要。
适用事件 | 事件数据格式 |
---|---|
|
command_id=" |
|
name=" |
|
sql_command_id=" |
|
db=" |
在 null_audit_event_order_check
值中,在事件字符串的 command
部分中指定 ABORT_RET
可以中止对指定事件的审核 API 调用。(假设该事件是可以中止的事件。之前已描述了哪些事件不可中止。)例如,如前所述,这是对 t1
进行插入的预期事件顺序
MYSQL_AUDIT_COMMAND_START;command_id="3";
MYSQL_AUDIT_PARSE_PREPARSE;;
MYSQL_AUDIT_PARSE_POSTPARSE;;
MYSQL_AUDIT_GENERAL_LOG;;
MYSQL_AUDIT_QUERY_START;sql_command_id="5";
MYSQL_AUDIT_TABLE_ACCESS_INSERT;db="db1" table="t1";
MYSQL_AUDIT_QUERY_STATUS_END;sql_command_id="5";
MYSQL_AUDIT_GENERAL_RESULT;;
MYSQL_AUDIT_GENERAL_STATUS;;
MYSQL_AUDIT_COMMAND_END;command_id="3";
要在发生 MYSQL_AUDIT_QUERY_STATUS_END
事件时中止 INSERT
语句的执行,请将 null_audit_event_order_check
设置为以下值(请记住在相邻事件字符串之间添加分号分隔符)
SET @@null_audit_event_order_check =
'MYSQL_AUDIT_COMMAND_START;command_id="3";;'
'MYSQL_AUDIT_PARSE_PREPARSE;;;'
'MYSQL_AUDIT_PARSE_POSTPARSE;;;'
'MYSQL_AUDIT_GENERAL_LOG;;;'
'MYSQL_AUDIT_QUERY_START;sql_command_id="5";;'
'MYSQL_AUDIT_TABLE_ACCESS_INSERT;db="db1" table="t1";;'
'MYSQL_AUDIT_QUERY_STATUS_END;sql_command_id="5";ABORT_RET';
不必列出预计在包含 command
值为 ABORT_RET
的事件字符串之后发生的事件。
在审核插件匹配完前面的序列后,它会中止事件处理并将错误消息发送到客户端。它还会将 null_audit_event_order_check
设置为 EVENT-ORDER-ABORT
mysql> INSERT INTO db1.t1 VALUES ('some data');
ERROR 3164 (HY000): Aborted by Audit API ('MYSQL_AUDIT_QUERY_STATUS_END';1).
mysql> SELECT @@null_audit_event_order_check;
+--------------------------------+
| @@null_audit_event_order_check |
+--------------------------------+
| EVENT-ORDER-ABORT |
+--------------------------------+
从审核 API 通知例程中返回非零值是中止事件执行的标准方法。也可以通过将 null_audit_abort_value
变量设置为通知例程应返回的值来指定自定义错误代码
SET @@null_audit_abort_value = 123;
中止序列会导致包含自定义错误代码的标准消息。假设您这样设置审计日志系统变量,以便在针对执行 SELECT 1
语句发生的事件匹配时中止。
SET @@null_audit_abort_value = 123;
SET @@null_audit_event_order_check =
'MYSQL_AUDIT_COMMAND_START;command_id="3";;'
'MYSQL_AUDIT_PARSE_PREPARSE;;;'
'MYSQL_AUDIT_PARSE_POSTPARSE;;;'
'MYSQL_AUDIT_GENERAL_LOG;;;'
'MYSQL_AUDIT_QUERY_START;sql_command_id="0";ABORT_RET';
那么,执行 SELECT 1
会导致包含自定义错误代码的以下错误消息。
mysql> SELECT 1;
ERROR 3164 (HY000): Aborted by Audit API ('MYSQL_AUDIT_QUERY_START';123).
mysql> SELECT @@null_audit_event_order_check;
+--------------------------------+
| @@null_audit_event_order_check |
+--------------------------------+
| EVENT-ORDER-ABORT |
+--------------------------------+
也可以通过设置 null_audit_abort_message
变量,使用自定义消息中止事件。假设您这样设置审计日志系统变量。
SET @@null_audit_abort_message = 'Custom error text.';
SET @@null_audit_event_order_check =
'MYSQL_AUDIT_COMMAND_START;command_id="3";;'
'MYSQL_AUDIT_PARSE_PREPARSE;;;'
'MYSQL_AUDIT_PARSE_POSTPARSE;;;'
'MYSQL_AUDIT_GENERAL_LOG;;;'
'MYSQL_AUDIT_QUERY_START;sql_command_id="0";ABORT_RET';
那么,中止序列会导致以下错误消息。
mysql> SELECT 1;
ERROR 3164 (HY000): Custom error text.
mysql> SELECT @@null_audit_event_order_check;
+--------------------------------+
| @@null_audit_event_order_check |
+--------------------------------+
| EVENT-ORDER-ABORT |
+--------------------------------+
要禁用 NULL_AUDIT
插件(测试完后),请使用以下语句卸载它。
UNINSTALL PLUGIN NULL_AUDIT;