28.2.4.8 编写审核插件

本节介绍如何使用 MySQL 源代码发行版本plugin/audit_null目录中的示例插件编写服务器端审核插件。该目录中的audit_null.caudit_null_variables.h源文件实现了名为NULL_AUDIT的审核插件。

Note

MySQL 5.7 中进行了更改,以将查询重写插件重新实现为审核插件,并且与 MySQL 5.6 相比,审核插件 API 本身进行了广泛的修订。要针对旧版 API 编写审核插件,请参见MySQL 5.6 参考手册中的编写审核插件

Note

使用审核插件 API 的插件的其他示例是查询重写插件(请参见第 5.5.4 节“重写器查询重写插件”)和版本令牌插件(请参见第 5.5.5 节“版本令牌”)。

在服务器内部,可插入审核接口在 MySQL 源分发的sql目录中的sql_audit.hsql_audit.cc文件中实现。此外,发生可审核事件时,服务器中的多个位置会调用审核接口,以便在必要时可以将事件通知给已注册的审核插件。若要查看发生此类调用的位置,请在服务器源文件中搜索名称为mysql_audit_xxx()形式的函数的调用。发生以下服务器操作的审核通知:

  • Client 端连接和断开事件

  • 将消息写入常规查询日志(如果已启用日志)

  • 将消息写入错误日志

  • 发送查询结果给 Client 端

要编写审核插件,请在插件源文件中包含以下头文件。根据插件的功能和要求,可能还需要其他 MySQL 或常规头文件。

#include <mysql/plugin_audit.h>

plugin_audit.h包含plugin.h,因此您无需显式包括后者。 plugin.h定义MYSQL_AUDIT_PLUGIN服务器插件类型和声明插件所需的数据结构。 plugin_audit.h定义特定于审核插件的数据结构。

审核插件通用 Descriptors

审核插件与任何 MySQL 服务器插件一样,具有通用的插件 Descriptors(请参见第 28.2.4.2.1 节,“服务器插件库和插件 Descriptors”)和特定于类型的插件 Descriptors。在audit_null.c中,audit_null的一般 Descriptors 如下所示:

mysql_declare_plugin(audit_null)
{
  MYSQL_AUDIT_PLUGIN,         /* type                            */
  &audit_null_descriptor,     /* descriptor                      */
  "NULL_AUDIT",               /* name                            */
  "Oracle Corp",              /* 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指向特定于类型的插件 Descriptors,稍后将进行描述。

name成员(NULL_AUDIT)table 示在诸如INSTALL PLUGINUNINSTALL PLUGIN之类的语句中用于引用插件的名称。这也是INFORMATION_SCHEMA.PLUGINSSHOW PLUGINS显示的名称。

插件加载后,audit_null_plugin_init初始化函数将执行插件初始化。插件卸载后,audit_null_plugin_deinit函数执行清理。

通用插件 Descriptors 还引用simple_statussystem_variables,它们公开了几个状态和系统变量。启用插件后,可以使用SHOW语句(SHOW STATUSSHOW VARIABLES)或适当的性能模式 table 来检查这些变量。

simple_status结构声明名称为Audit_null_xxx形式的几个状态变量。 NULL_AUDIT为收到的每个通知增加Audit_null_called状态变量。其他状态变量则更具体,并且NULL_AUDIT仅针对特定事件的通知将其递增。

system_variables是系统变量元素的数组,每个元素都是使用MYSQL_THDVAR_xxx宏定义的。这些系统变量的名称格式为null_audit_xxx。这些变量可用于在运行时与插件通信。

特定于审计插件类型的 Descriptors

常规插件 Descriptors 中的audit_null_descriptor值指向特定于类型的插件 Descriptors。对于审核插件,此 Descriptors 具有以下结构(在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];
};

审计插件的特定于类型的 Descriptors 具有以下成员:

  • interface_version:按照惯例,类型特定的插件 Descriptors 以给定插件类型的接口版本开头。服务器在加载插件时会检查interface_version,以查看插件是否与其兼容。对于审核插件,interface_version成员的值为MYSQL_AUDIT_INTERFACE_VERSION(在plugin_audit.h中定义)。

  • release_thd:服务器调用此函数以通知插件它正在与其线程上下文分离。如果没有此功能,则应为NULL

  • event_notify:服务器调用此功能以通知插件已发生可审核的事件。此函数不应为NULL;这是没有意义的,因为不会进行审核。

  • class_maskMYSQL_AUDIT_CLASS_MASK_SIZE个元素的数组。每个元素为给定的事件类指定一个位掩码,以指示插件要为其通知的子类。 (这是插件“订阅”感兴趣事件的方式.)元素应为 0,以忽略相应事件类的所有事件。

服务器一起使用event_notifyrelease_thd功能。在特定线程的上下文中调用它们,并且线程可能执行产生多个事件通知的活动。服务器第一次为线程调用event_notify时,会创建插件与线程的绑定。存在此绑定时,无法卸载该插件。当不再发生该线程的事件时,服务器将通过调用release_thd函数将此通知插件,然后销毁绑定。例如,当 Client 发出一条语句时,处理该语句的线程可能会通知审计插件有关该语句产生的结果集和正在记录的语句的信息。发生这些通知后,服务器将释放插件,然后将线程置于睡眠状态,直到 Client 端发出另一条语句。

这种设计使插件可以在第一次调用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审核插件,特定于类型的插件 Descriptors 如下所示:

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_ALL符号,它是所有子类位掩码的并集。例如,对于MYSQL_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元素(在本例中为class_mask[1])中指定MYSQL_AUDIT_CONNECTION_ALL。要仅订阅某些子类,该插件将class_mask元素设置为感兴趣的子类的并集。例如,仅订阅 connect 和 change-user 子类,插件将class_mask[1]设置为此值:

MYSQL_AUDIT_CONNECTION_CONNECT | MYSQL_AUDIT_CONNECTION_CHANGE_USER
审核插件通知功能

审核插件的大部分工作都在通知功能(特定于类型的插件 Descriptors 的event_notify成员)中进行。服务器为每个可审核事件调用此函数。审核插件通知功能具有以下原型:

int (*event_notify)(MYSQL_THD, mysql_event_class_t, const void *);

event_notify函数原型的第二个和第三个参数 table 示事件类和指向事件结构的通用指针。 (不同类中的事件具有不同的结构.通知函数可以使用事件类的值来确定采用哪种事件结构.)该函数处理事件并返回一个状态,指示服务器是应 continue 处理该事件还是终止该事件。

对于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()将事件强制转换为适当的类特定结构,然后检查其子类以确定要递增的子类计数器。例如,用于处理 connection-event 类中的事件的代码如下所示:

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;
  }
}

Note

一般事件类(MYSQL_AUDIT_GENERAL_CLASS)已被弃用,并将在以后的 MySQL 版本中删除。为了减少插件开销,最好只订阅感兴趣的更特定的事件类。

对于某些事件类,NULL_AUDIT插件除了增加计数器外还执行其他处理。无论如何,当通知功能完成事件处理后,它应返回一个状态,指示服务器是 continue 处理该事件还是终止该事件。

审核插件错误处理

审核插件通知功能可以通过两种方式报告当前事件的状态值:

  • 使用通知函数的返回值。在这种情况下,如果服务器应 continue 处理事件,则该函数将返回零;如果服务器应终止该事件,则该函数将返回非零。

  • 从通知功能返回之前,调用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:服务器无法阻止 Client 端断开连接。

  • MYSQL_AUDIT_COMMAND_END:此事件提供已完成执行的命令的状态,因此无意终止它。

如果审核插件针对不可确定的事件返回非零状态,则服务器将忽略状态并 continue 处理该事件。如果审核插件使用my_message()函数来终止不可确定的事件,则也是如此。

审核插件的使用

要编译和安装插件库文件,请使用第 28.2.4.3 节“编译和安装插件库”中的说明。要使该库文件可供使用,请将其安装在插件目录(由plugin_dir系统变量命名的目录)中。对于NULL_AUDIT插件,当您从源代码构建 MySQL 时会对其进行编译和安装。它也包含在二进制发行版中。构建过程将生成一个共享对象库,其名称为adt_null.so(后缀.so可能因平台而异)。

要在运行时注册插件,请使用以下语句,并根据需要调整平台的.so后缀:

INSTALL PLUGIN NULL_AUDIT SONAME 'adt_null.so';

有关插件加载的其他信息,请参见第 5.5.1 节“安装和卸载插件”

要验证插件安装,请检查INFORMATION_SCHEMA.PLUGINStable 或使用SHOW PLUGINS语句。参见第 5.5.2 节“获取服务器插件信息”

安装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_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语句使服务器将结果发送到 Client 端,并将消息写入通用查询日志(如果启用了该日志)。因此,重复发出该语句的 Client 端使Audit_null_calledAudit_null_general_resultAudit_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:事件匹配之前,应按预期的事件 Sequences 排列。事件匹配后,匹配结果。

  • null_audit_event_order_check_consume_ignore_count:事件匹配不应消耗匹配事件的次数。

  • null_audit_event_order_check_exact:事件匹配是否必须精确。禁用此变量将启用在事件 Sequences 匹配过程中跳过null_audit_event_order_check中未列出的事件。在指定的事件中,它们仍必须按照给定的 Sequences 进行匹配。

  • null_audit_event_order_started:供内部使用。

  • null_audit_event_record:发生事件记录后记录的事件。

  • null_audit_event_record_def:记录事件时要匹配的开始和结束事件的名称,以分号分隔。必须在每个记录事件的语句之前设置该值。

为了演示这些系统变量的用法,假设存在一个 tabledb1.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 *:为空,或者如稍后所述,匹配事件时执行的命令。

Note

NULL_AUDIT插件的局限性在于事件记录仅适用于单个会话。在给定会话中记录事件后,在随后的会话中记录事件将产生NULLnull_audit_event_record值。要再次记录事件,必须重新启动插件。

要检查审核 API 调用的 Sequences,请将null_audit_event_order_check变量设置为特定操作的预期事件 Sequences,列出一个或多个事件字符串,每个事件字符串内部包含两个分号,并使用其他分号分隔相邻的事件字符串:

event_name;event_data;command [;event_name;event_data;command] ...

For example:

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变量设置为事件字符串列 table 之后,下一个匹配操作将变量值替换为指示操作结果的值:

  • 如果预期事件 Sequences 成功匹配,则结果null_audit_event_order_check值为EVENT-ORDER-OK

  • 如果指定的null_audit_event_order_check值终止匹配事件(如稍后所述),则结果null_audit_event_order_check值为EVENT-ORDER-ABORT

  • 如果预期事件 Sequences 因意外数据而失败,则结果null_audit_event_order_check值为EVENT-ORDER-INVALID-DATA。例如,如果指定了一个预期影响 tablet1但实际上影响t2的事件,则会发生这种情况。

当您将要匹配的事件列 table 分配给null_audit_event_order_check时,应使用事件字符串的非空* event_data 部分来指定某些事件。下 table 显示了这些事件的 event_data 格式。如果事件使用多个数据值,则必须按照显示的 Sequences 指定它们。或者,可以将 event_data *值指定为<IGNORE>以忽略事件数据内容;在这种情况下,事件是否具有数据并不重要。

Applicable Events事件数据格式
MYSQL_AUDIT_COMMAND_START

MYSQL_AUDIT_COMMAND_END
command_id="id_value"
MYSQL_AUDIT_GLOBAL_VARIABLE_GET
MYSQL_AUDIT_GLOBAL_VARIABLE_SET
name="var_value" value="var_value"
MYSQL_AUDIT_QUERY_NESTED_START
MYSQL_AUDIT_QUERY_NESTED_STATUS_END
MYSQL_AUDIT_QUERY_START
MYSQL_AUDIT_QUERY_STATUS_END
sql_command_id="id_value"
MYSQL_AUDIT_TABLE_ACCESS_DELETE
MYSQL_AUDIT_TABLE_ACCESS_INSERT
MYSQL_AUDIT_TABLE_ACCESS_READ
MYSQL_AUDIT_TABLE_ACCESS_UPDATE
db="db_name" table="table_name"

null_audit_event_order_check值中,在事件字符串的* command *部分中指定ABORT_RET可以中止对指定事件的审核 API 调用。 (假设该事件是可以中止的事件.那些先前无法描述的事件.)例如,如前所示,这是插入t1的事件的预期 Sequences:

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的事件字符串之后发生。

审计插件与前面的序列匹配后,它将中止事件处理并将错误消息发送给 Client 端。还将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;