6.4.5.8 编写审核日志过滤器定义

过滤器定义是JSON个值。有关在 MySQL 中使用JSON数据的信息,请参见第 11.5 节“ JSON 数据类型”

过滤器定义具有以下形式,其中* actions *table 示过滤的方式:

{ "filter": actions }

以下讨论描述了过滤器定义中允许的构造。

记录所有事件

要显式启用或禁用所有事件的日志记录,请在过滤器中使用log元素:

{
  "filter": { "log": true }
}

log的值可以是truefalse

前面的过滤器允许记录所有事件。它等效于:

{
  "filter": { }
}

记录行为取决于log值以及是否指定了classevent项:

  • 指定log时,将使用其给定值。

  • 如果未指定log,则如果未指定classevent项,则日志记录为true,否则为false(在这种情况下classevent可以包括自己的log项)。

记录特定的事件类

要记录特定类的事件,请在过滤器中使用class元素,其name字段 table 示要记录的类的名称:

{
  "filter": {
    "class": { "name": "connection" }
  }
}

name的值可以是connectiongeneraltable_access来分别记录连接事件,常规事件或 table 访问事件。

通过前面的过滤器,可以记录connection类中的事件。它等效于以下带有明确显示的log项的过滤器:

{
  "filter": {
    "log": false,
    "class": { "log": true,
               "name": "connection" }
  }
}

要启用多个类的日志记录,请将class值定义为命名这些类的JSON数组元素:

{
  "filter": {
    "class": [
      { "name": "connection" },
      { "name": "general" },
      { "name": "table_access" }
    ]
  }
}

Note

当给定项目的多个实例出现在过滤器定义中的同一级别时,可以将项目值组合到数组值内该项目的单个实例中。前面的定义可以这样写:

{
"filter": {
"class": [
{ "name": [ "connection", "general", "table_access" ] }
]
}
}
记录特定事件子类

若要选择特定的事件子类,请使用event项,其中name项为子类命名。 event项选择的事件的默认操作是记录它们。例如,此过滤器允许记录命名事件子类:

{
  "filter": {
    "class": [
      {
        "name": "connection",
        "event": [
          { "name": "connect" },
          { "name": "disconnect" }
        ]
      },
      { "name": "general" },
      {
        "name": "table_access",
        "event": [
          { "name": "insert" },
          { "name": "delete" },
          { "name": "update" }
        ]
      }
    ]
  }
}

event项还可以包含明确的log项,以指示是否记录合格事件。 event项选择多个事件并明确指示它们的日志记录行为:

"event": [
  { "name": "read", "log": false },
  { "name": "insert", "log": true },
  { "name": "delete", "log": true },
  { "name": "update", "log": true }
]

从 MySQL 5.7.20 开始,如果event项包含abort项,它也可以指示是否阻止合格事件。有关详细信息,请参见阻止特定事件的执行

table6.26,“事件类和子类组合”描述了每个事件类的允许子类值。

table6.26 事件类和子类组合

Event ClassEvent SubclassDescription
connectionconnect连接启动(成功或失败)
connectionchange_user会话期间使用不同的用户/密码进行用户重新认证
connectiondisconnectConnection termination
generalstatus一般操作信息
table_accessreadtable 读取语句,例如SELECT插入...选择
table_accessdeletetable 删除语句,例如DELETETRUNCATE TABLE
table_accessinserttable 插入语句,例如INSERTREPLACE
table_accessupdatetable 更新语句,例如UPDATE

table6.27,“每个事件类和子类组合的日志和异常特性”描述每个事件子类是否可以记录或中止。

table6.27 每个事件类和子类组合的日志和异常特性

Event ClassEvent Subclass可以记录可以中止
connectionconnectYesNo
connectionchange_userYesNo
connectiondisconnectYesNo
generalstatusYesNo
table_accessreadYesYes
table_accessdeleteYesYes
table_accessinsertYesYes
table_accessupdateYesYes
独占记录

可以以包含或排除模式定义过滤器:

  • 包含模式仅记录明确指定的项目。

  • 独占模式记录除明确指定的项目以外的所有内容。

要执行包含性日志记录,请全局禁用日志记录并启用特定类的日志记录。此过滤器记录connection类中的connectdisconnect事件,以及general类中的事件:

{
  "filter": {
    "log": false,
    "class": [
      {
        "name": "connection",
        "event": [
          { "name": "connect", "log": true },
          { "name": "disconnect", "log": true }
        ]
      },
      { "name": "general", "log": true }
    ]
  }
}

要执行独占日志记录,请全局启用日志记录,并禁用特定类的日志记录。此过滤器记录除general类中的事件以外的所有内容:

{
  "filter": {
    "log": true,
    "class":
      { "name": "general", "log": false }
  }
}

此过滤器通过* not *记录其他所有内容,从而记录connection类中的change_user事件和table_access事件:

{
  "filter": {
    "log": true,
    "class": [
      {
        "name": "connection",
        "event": [
          { "name": "connect", "log": false },
          { "name": "disconnect", "log": false }
        ]
      },
      { "name": "general", "log": false }
    ]
  }
}
测试事件字段值

要启用基于特定事件字段值的日志记录,请在log项中指定一个field项,以指示字段名称及其期望值:

{
  "filter": {
    "class": {
    "name": "general",
      "event": {
        "name": "status",
        "log": {
          "field": { "name": "general_command.str", "value": "Query" }
        }
      }
    }
  }
}

每个事件都包含特定于事件类的字段,可以从过滤器内部访问这些字段以执行自定义过滤。

连接事件指示会话期间何时发生与连接有关的活动,例如用户连接到服务器或从服务器断开连接。 table6.28,“连接事件字段”table 示连接事件的允许字段。

table6.28 连接事件字段

Field NameField TypeDescription
statusintegerEvent status:

0: OK
Otherwise: Failed
connection_id无符号整数连接 ID
user.str字符串认证期间指定的用户名
user.length无符号整数用户名长度
priv_user.str字符串授权的用户名(帐户用户名)
priv_user.length无符号整数授权的用户名长度
external_user.strstring外部用户名(由第三方身份验证插件提供)
external_user.length无符号整数外部用户名长度
proxy_user.str字符串代理用户名
proxy_user.length无符号整数代理用户名长度
host.str字符串连接的用户主机
host.length无符号整数连接的用户主机长度
ip.str字符串连接的用户 IP 地址
ip.length无符号整数连接的用户 IP 地址长度
database.str字符串在连接时指定的数据库名称
database.length无符号整数数据库名称长度
connection_type整数连接类型:
"::undefined":未定义
"::tcp/ip":TCP/IP
"::socket":套接字
"::named_pipe":命名管道
"::ssl":具有加密功能的 TCP/IP
"::shared_memory":共享内存

"::xxx"值是符号伪常量,可以代替 Literals 数字值来给出。它们必须用字符串引号并且区分大小写。

常规事件指示操作的状态码及其详细信息。 table6.29,“常规事件字段”table 示一般事件的允许字段。

table6.29 常规事件字段

Field NameField TypeDescription
general_error_codeintegerEvent status:

0: OK
Otherwise: Failed
general_thread_id无符号整数连接/线程 ID
general_user.str字符串认证期间指定的用户名
general_user.length无符号整数用户名长度
general_command.str字符串命令名称
general_command.length无符号整数命令名称长度
general_query.str字符串SQL 语句文本
general_query.length无符号整数SQL 语句文本长度
general_host.str字符串主机名
general_host.length无符号整数主机名长度
general_sql_command.str字符串SQL 命令类型名称
general_sql_command.length无符号整数SQL 命令类型名称长度
general_external_user.strstring外部用户名(由第三方身份验证插件提供)
general_external_user.length无符号整数外部用户名长度
general_ip.str字符串连接的用户 IP 地址
general_ip.length无符号整数连接用户 IP 地址长度

general_command.strtable 示命令名称:QueryExecuteQuitChange user

general_command.str字段设置为QueryExecute的一般事件包含general_sql_command.str设置为一个值,该值指定 SQL 命令的类型:alter_dbalter_db_upgradeadmin_commands等。这些值可以视为此语句显示的性能模式工具的最后一个组件:

mysql> SELECT NAME FROM performance_schema.setup_instruments
       WHERE NAME LIKE 'statement/sql/%' ORDER BY NAME;
+---------------------------------------+
| NAME                                  |
+---------------------------------------+
| statement/sql/alter_db                |
| statement/sql/alter_db_upgrade        |
| statement/sql/alter_event             |
| statement/sql/alter_function          |
| statement/sql/alter_instance          |
| statement/sql/alter_procedure         |
| statement/sql/alter_server            |
...

table 访问事件提供有关特定 table 访问的信息。 table6.30,“table 访问事件字段”table 示 table 访问事件的允许字段。

table6.30table 访问事件字段

Field NameField TypeDescription
connection_idunsigned integer事件连接 ID
sql_command_idintegerSQL 命令 ID
query.strstringSQL 语句文本
query.lengthunsigned integerSQL 语句文本长度
table_database.strstring与事件关联的数据库名称
table_database.lengthunsigned integer数据库名称长度
table_name.strstring与事件关联的 table 名
table_name.lengthunsigned integertable 名长度

以下列 table 显示哪些语句产生哪些 table 访问事件:

  • read事件:

  • SELECT

    • INSERT ... SELECT(用于SELECT子句中引用的 table)

    • REPLACE ... SELECT(用于SELECT子句中引用的 table)

    • UPDATE ... WHERE(用于WHERE子句中引用的 table)

    • HANDLER ... READ

  • delete事件:

  • DELETE

    • TRUNCATE TABLE
  • insert事件:

  • INSERT

    • INSERT ... SELECT(用于INSERT子句中引用的 table)

    • REPLACE

    • REPLACE ... SELECT(用于REPLACE子句中引用的 table

    • LOAD DATA

    • LOAD XML

  • update事件:

  • UPDATE

    • UPDATE ... WHERE(用于UPDATE子句中引用的 table)
阻止执行特定事件

从 MySQL 5.7.20 开始,event项可以包含abort项,指示是否防止执行限定事件。例如,abort允许编写阻止特定 SQL 语句执行的规则。

abort项必须出现在event项中。例如:

"event": {
  "name": qualifying event subclass names
  "abort": condition
}

对于name项选择的事件子类,abort动作是 true 还是 false,取决于* condition *评估。如果条件评估为真,则事件被阻止。否则,事件将 continue 执行。

  • condition *规范可以像truefalse一样简单,也可以更复杂,以便评估取决于事件 Feature。

此过滤器阻止INSERTUPDATEDELETE语句:

{
  "filter": {
    "class": {
      "name": "table_access",
      "event": {
        "name": [ "insert", "update", "delete" ],
        "abort": true
      }
    }
  }
}

这个更复杂的过滤器将阻止相同的语句,但仅针对特定的 table(finances.bank_account):

{
  "filter": {
    "class": {
      "name": "table_access",
      "event": {
        "name": [ "insert", "update", "delete" ],
        "abort": {
          "and": [
            { "field": { "name": "table_database.str", "value": "finances" } },
            { "field": { "name": "table_name.str", "value": "bank_account" } }
          ]
        }
      }
    }
  }
}

过滤器匹配和阻止的语句向 Client 端返回错误:

ERROR 1045 (28000): Statement was aborted by an audit log filter

并非所有事件都可以被阻止(请参阅table6.27,“每个事件类和子类组合的日志和异常特性”)。对于无法处理的事件,审核日志会将警告写入错误日志,而不是阻止警告。

如果试图定义一个过滤器,其中abort项出现在event项之外的其他位置,则会发生错误。

Logical Operators

逻辑运算符(andornot)可用于log个项目。这允许构建更高级的过滤配置:

{
  "filter": {
    "class": {
      "name": "general",
      "event": {
        "name": "status",
        "log": {
          "or": [
            {
              "and": [
                { "field": { "name": "general_command.str",    "value": "Query" } },
                { "field": { "name": "general_command.length", "value": 5 } }
              ]
            },
            {
              "and": [
                { "field": { "name": "general_command.str",    "value": "Execute" } },
                { "field": { "name": "general_command.length", "value": 7 } }
              ]
            }
          ]
        }
      }
    }
  }
}
引用 sched 义变量

要在log条件下引用 sched 义变量,请使用variable项目,该项目针对给定值测试是否相等:

{
  "filter": {
    "class": {
      "name": "general",
      "event": {
        "name": "status",
        "log": {
          "variable": {
            "name": "audit_log_connection_policy_value", "value": "::none"
          }
        }
      }
    }
  }
}

每个 sched 义变量对应于一个系统变量。通过编写用于测试 sched 义变量的过滤器,您可以通过设置相应的系统变量来修改过滤器操作,而不必重新定义过滤器。例如,通过编写测试audit_log_connection_policy_valuesched 义变量的值的过滤器,可以通过更改audit_log_connection_policy系统变量的值来修改过滤器操作。

audit_log_xxx_policy系统变量用于旧模式审核日志(请参见第 6.4.5.9 节“旧模式审核日志过滤”)。使用基于规则的审核日志过滤时,这些变量保持可见(例如,使用SHOW VARIABLES),但是除非您编写包含引用它们的构造的过滤器,否则对它们的更改将无效。

以下列 table 描述了variable个项目的允许 sched 义变量:

  • audit_log_connection_policy_value

此变量对应于audit_log_connection_policy系统变量的值。该值是无符号整数。 table6.31,“ audit_log_connection_policy_value 值”显示允许的值和相应的audit_log_connection_policy值。

table6.31 audit_log_connection_policy_value 的值

Value对应的 audit_log_connection_policy 值
0"::none"NONE
1"::errors"ERRORS
2"::all"ALL

"::xxx"值是符号伪常量,可以代替 Literals 数字值来给出。它们必须用字符串引号并且区分大小写。

  • audit_log_policy_value

此变量对应于audit_log_policy系统变量的值。该值是无符号整数。 table6.32,“ audit_log_policy_value 值”显示允许的值和相应的audit_log_policy值。

table6.32 audit_log_policy_value 的值

Value对应的 audit_log_policy 值
0"::none"NONE
1"::logins"LOGINS
2"::all"ALL
3"::queries"QUERIES

"::xxx"值是符号伪常量,可以代替 Literals 数字值来给出。它们必须用字符串引号并且区分大小写。

  • audit_log_statement_policy_value

此变量对应于audit_log_statement_policy系统变量的值。该值是无符号整数。 table6.33,“ audit_log_statement_policy_value 值”显示允许的值和相应的audit_log_statement_policy值。

table6.33 audit_log_statement_policy_value 的值

Value对应的 audit_log_statement_policy 值
0"::none"NONE
1"::errors"ERRORS
2"::all"ALL

"::xxx"值是符号伪常量,可以代替 Literals 数字值来给出。它们必须用字符串引号并且区分大小写。

引用 sched 义函数

要在log条件下引用 sched 义函数,请使用function项,该项采用nameargs值分别指定函数名称及其参数:

{
  "filter": {
    "class": {
      "name": "general",
      "event": {
        "name": "status",
        "log": {
          "function": {
            "name": "find_in_include_list",
            "args": [ { "string": [ { "field": "user.str" },
                                    { "string": "@"},
                                    { "field": "host.str" } ] } ]
          }
        }
      }
    }
  }
}

name项中指定的函数只能是函数名称,不能带括号或参数列 table。 args项中的参数(如果有)必须按功能说明中列出的 Sequences 给出。参数可以引用 sched 义的变量,事件字段或字符串或数字常量。

前面的过滤器根据是否在audit_log_include_accounts系统变量中找到当前用户来确定是否记录generalstatus事件。该用户是使用事件中的字段构造的。

以下列 table 描述了function个项目允许的 sched 义功能:

  • audit_log_exclude_accounts_is_null()

检查audit_log_exclude_accounts系统变量是否为NULL。当定义与旧审计日志实现相对应的过滤器时,此功能可能会很有帮助。

Arguments:

None.

  • audit_log_include_accounts_is_null()

检查audit_log_include_accounts系统变量是否为NULL。当定义与旧审计日志实现相对应的过滤器时,此功能可能会很有帮助。

Arguments:

None.

  • debug_sleep(millisec)

睡眠指定的毫秒数。在性能测量期间使用此功能。

debug_sleep()仅适用于调试版本。

Arguments:

    • millisec *:一个无符号整数,指定要睡眠的毫秒数。
  • find_in_exclude_list(account)

检查审核日志排除列 table 中是否存在帐户字符串(audit_log_exclude_accounts系统变量的值)。

Arguments:

    • account *:指定用户帐户名称的字符串。
  • find_in_include_list(account)

检查审核日志包含列 table(audit_log_include_accounts系统变量的值)中是否存在帐户字符串。

Arguments:

    • account *:指定用户帐户名称的字符串。
  • string_find(text, substr)

检查substr值是否包含在text值中。此搜索区分大小写。

Arguments:

    • text *:要搜索的文本字符串。
      • substr :要在 text *中搜索的子字符串。
替换用户过滤器

在某些情况下,可以动态更改过滤器定义。为此,请在现有的filter中定义filter配置。例如:

{
  "filter": {
    "id": "main",
    "class": {
      "name": "table_access",
      "event": {
        "name": [ "update", "delete" ],
        "log": false,
        "filter": {
          "class": {
            "name": "general",
            "event" : { "name": "status",
                        "filter": { "ref": "main" } }
          },
          "activate": {
            "or": [
              { "field": { "name": "table_name.str", "value": "temp_1" } },
              { "field": { "name": "table_name.str", "value": "temp_2" } }
            ]
          }
        }
      }
    }
  }
}

当子过滤器中的activate元素的值为true时,将激活一个新的过滤器。不允许在顶级filter中使用activate

通过使用子过滤器中的ref项来引用原始过滤器id,可以用原始过滤器替换新的过滤器。

所示过滤器的操作如下:

  • main过滤器 awaittable_access事件,即updatedelete

  • 如果temp_1temp_2table 上发生了updatedelete table_access事件,则将过滤器替换为内部过滤器(没有id,因为不需要显式引用它)。

  • 如果发出命令结束的 signal(general/status事件),则会将一个条目写入审核日志文件,并将该过滤器替换为main过滤器。

该过滤器对于记录更新或删除temp_1temp_2table 中的内容的语句很有用,例如:

UPDATE temp_1, temp_3 SET temp_1.a=21, temp_3.a=23;

该语句生成多个table_access事件,但是审核日志文件将仅包含general/status条目。

Note

定义中使用的任何id值仅针对该定义进行评估。它们与audit_log_filter_id系统变量的值无关。