擴充 MySQL 8.4  /  ...  /  編寫稽核外掛程式

4.4.8 編寫稽核外掛程式

本節說明如何編寫伺服器端稽核外掛程式,使用 MySQL 原始碼發行版本中的 plugin/audit_null 目錄下的範例外掛程式。該目錄中的 audit_null.caudit_null_variables.h 原始碼檔案實作名為 NULL_AUDIT 的稽核外掛程式。

注意

使用稽核外掛程式 API 的其他外掛程式範例為查詢重寫外掛程式(請參閱重寫器查詢重寫外掛程式)和版本權杖外掛程式(請參閱版本權杖)。

在伺服器內部,可插入稽核介面實作於 MySQL 原始碼發行版本的 sql 目錄下的 sql_audit.hsql_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 PLUGINUNINSTALL PLUGIN) 中用於參考外掛程式的名稱。這也是 INFORMATION_SCHEMA.PLUGINSSHOW PLUGINS 所顯示的名稱。

audit_null_plugin_init 初始化函式會在載入外掛程式時執行外掛程式初始化。audit_null_plugin_deinit 函式會在卸載外掛程式時執行清除。

一般外掛程式描述符也會參考 simple_statussystem_variables,這些結構會公開數個狀態和系統變數。啟用外掛程式時,可以使用 SHOW 陳述式 (SHOW STATUSSHOW VARIABLES) 或適當的效能結構描述表格來檢查這些變數。

simple_status 結構宣告數個狀態變數,其名稱形式為 Audit_null_xxxNULL_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_maskMYSQL_AUDIT_CLASS_MASK_SIZE 元素的陣列。每個元素都為給定事件類別指定位元遮罩,以指示外掛程式想要通知的子類別。(這是外掛程式「訂閱」感興趣事件的方式。) 若要忽略對應事件類別的所有事件,元素應為 0。

伺服器會一起使用 event_notifyrelease_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_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 元素設定為感興趣的子類別的聯集。例如,要僅訂閱連線和變更使用者子類別,外掛程式會將 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_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:在事件比對之前,預期的事件順序。在事件比對之後,比對結果。

  • 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_audit_event_recordNULL。若要再次記錄事件,必須重新啟動外掛程式。

若要檢查稽核 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> 以忽略事件資料內容;在這種情況下,事件是否有資料並不重要。

適用事件 事件資料格式

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 的事件預期順序

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;