Documentation Home
MySQL 8.0 参考手册  / 第 6 章 安全  / 6.4 安全组件和插件  / 6.4.5 MySQL企业审计  /  6.4.5.8 编写审计日志过滤器定义

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

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

过滤器定义具有这种形式,其中 actions指示过滤是如何发生的:

{ "filter": actions }

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

记录所有事件

要显式启用或禁用所有事件的日志记录,请使用 log过滤器中的一个项目:

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

log值可以是 truefalse

前面的过滤器启用所有事件的日志记录。它相当于:

{
  "filter": { }
}

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

  • 如果指定,则使用log其给定值。

  • 如果没有log指定,则记录是 true如果没有指定classevent项目, false否则(在这种情况下, classevent可以包括他们自己的log项目)。

记录特定事件类

要记录特定类的事件,请使用 class过滤器中的一个项目,其 name字段表示要记录的类的名称:

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

name值可以是 connectiongeneraltable_access以分别记录连接、一般或表访问事件。

前面的过滤器启用 connection类中事件的日志记录。它等效于以下带有log显式项的过滤器:

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

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

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

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

{
  "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项目。有关详细信息,请参阅 阻止执行特定事件

表 6.26 “事件类和子类组合” 描述了每个事件类允许的子类值。

表 6.26 事件类和子类组合

事件类 事件子类 描述
connection connect 连接启动(成功或不成功)
connection change_user 在会话期间使用不同的用户名/密码重新进行用户身份验证
connection disconnect 连接终止
general status 一般操作信息
table_access read 读表语句,例如SELECTor INSERT INTO ... SELECT
table_access delete 表删除语句,例如DELETE orTRUNCATE TABLE
table_access insert 表插入语句,例如INSERT orREPLACE
table_access update 表更新语句,如UPDATE

表 6.27,“每个事件类和子类组合的记录和中止特征”描述了每个事件子类是否可以记录或中止。

表 6.27 每个事件类和子类组合的日志和中止特征

事件类 事件子类 可以登录 可以中止
connection connect 是的
connection change_user 是的
connection disconnect 是的
general status 是的
table_access read 是的 是的
table_access delete 是的 是的
table_access insert 是的 是的
table_access update 是的 是的

包容性和独占性日志记录

过滤器可以定义为包含或独占模式:

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

  • 独占模式记录除显式指定项目之外的所有内容。

要执行包容性日志记录,请全局禁用日志记录并为特定类启用日志记录。这个过滤器日志 connect和类disconnect 中的事件connection,以及类中的事件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 }
  }
}

此过滤器记录类change_user中的事件 connectiontable_access事件,因为 记录其他所有内容:

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

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

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

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

类中的事件connection指示在会话期间何时发生与连接相关的活动,例如用户连接到服务器或从服务器断开连接。 表 6.28,“连接事件字段”指示事件的允许字段connection

表 6.28 连接事件字段

字段名称 字段类型 描述
status 整数

事件状态:

0:好的

否则:失败

connection_id 无符号整数 连接编号
user.str 细绳 认证时指定的用户名
user.length 无符号整数 用户名长度
priv_user.str 细绳 认证用户名(账户用户名)
priv_user.length 无符号整数 认证用户名长度
external_user.str 细绳 外部用户名(由第三方认证插件提供)
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 整数

连接类型:

0 或"::undefined":未定义

1 或"::tcp/ip":TCP/IP

2 或"::socket": 套接字

3 或"::named_pipe":命名管道

4 或"::ssl":加密的 TCP/IP

5 或"::shared_memory":共享内存


这些 值是可以给出的符号伪常量,而不是文字数值。它们必须作为字符串引用并且区分大小写。 "::xxx"

类中的事件general指示操作的状态代码及其详细信息。 表 6.29,“通用事件字段”指出了事件的允许字段general

表 6.29 一般事件字段

字段名称 字段类型 描述
general_error_code 整数

事件状态:

0:好的

否则:失败

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.str 细绳 外部用户名(由第三方认证插件提供)
general_external_user.length 无符号整数 外部用户名长度
general_ip.str 细绳 连接用户IP地址
general_ip.length 无符号整数 连接用户IP地址长度

general_command.str指示命令名称:QueryExecuteQuitChange user

字段设置为 或 包含设置为指定 SQL 命令类型的值 的general事件 : 、、、 等等 。可用 值可以看作是此语句显示的 Performance Schema 工具的最后一个组件: general_command.strQueryExecutegeneral_sql_command.stralter_dbalter_db_upgradeadmin_commandsgeneral_sql_command.str

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_access提供有关对表的特定类型访问的信息。 表 6.30,“表访问事件字段” 指示事件的允许字段 table_access

表 6.30 表访问事件字段

字段名称 字段类型 描述
connection_id 无符号整数 事件连接 ID
sql_command_id 整数 SQL 命令编号
query.str 细绳 SQL语句文本
query.length 无符号整数 SQL 语句文本长度
table_database.str 细绳 与事件关联的数据库名称
table_database.length 无符号整数 数据库名称长度
table_name.str 细绳 与事件关联的表名
table_name.length 无符号整数 表名长度

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

  • read事件:

    • SELECT

    • INSERT ... SELECTSELECT(对于子句 中引用的表格)

    • REPLACE ... SELECTSELECT(对于子句 中引用的表格)

    • UPDATE ... WHEREWHERE(对于子句 中引用的表格)

    • HANDLER ... READ

  • delete事件:

    • DELETE

    • TRUNCATE TABLE

  • insert事件:

    • INSERT

    • INSERT ... SELECT(对于INSERT子句中引用的表格)

    • REPLACE

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

    • LOAD DATA

    • LOAD XML

  • update事件:

    • UPDATE

    • UPDATE ... WHEREUPDATE(对于子句 中引用的表格)

阻止特定事件的执行

从 MySQL 5.7.20 开始,event项目可以包括一个abort项目,该项目指示是否阻止合格事件的执行。 abort允许编写阻止特定 SQL 语句执行的规则。

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

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

对于name 项目选择的事件子类,abort动作是真还是假,取决于condition评估。如果条件评估为真,则事件被阻止。否则,事件继续执行。

condition规范可以像true或 一样简单 ,false也可以更复杂,使得评估取决于事件特征。

此过滤器块INSERT, UPDATE, 和 DELETE语句:

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

这个更复杂的过滤器会阻止相同的语句,但只针对特定的表 ( 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" } }
          ]
        }
      }
    }
  }
}

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

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

并非所有事件都可以被阻止(请参阅 表 6.27,“每个事件类和子类组合的记录和中止特征”)。对于无法阻止的事件,审计日志会将警告写入错误日志而不是阻止它。

如果尝试定义 abort项目出现在项目以外的其他地方 的过滤器,event则会发生错误。

逻辑运算符

逻辑运算符 ( and, or, not) 允许构建复杂的条件,从而可以编写更高级的过滤配置。以下 log项目仅记录 具有特定值和长度 general的字段的事件 :general_command

{
  "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 } }
              ]
            }
          ]
        }
      }
    }
  }
}
引用预定义变量

要在条件中引用预定义变量log ,请使用一个variable项目,它采用 项目namevalue测试命名变量与给定值的相等性:

"variable": {
  "name": "variable_name",
  "value": comparison_value
}

如果variable_name具有 value则为 true comparison_value,否则为 false。

例子:

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

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

系统 变量用于遗留模式审计日志(请参阅 第 6.4.5.10 节,“遗留模式审计日志过滤”)。使用基于规则的审计日志过滤,这些变量保持可见(例如,使用),但对它们的更改没有效果,除非您编写包含引用它们的构造的过滤器。 audit_log_xxx_policySHOW VARIABLES

以下列表描述了variable项目允许的预定义变量:

  • audit_log_connection_policy_value

    该变量对应于 audit_log_connection_policy 系统变量的值。该值是一个无符号整数。 表 6.31 “audit_log_connection_policy_value 值” 显示了允许的值和相应的 audit_log_connection_policy 值。

    表 6.31 audit_log_connection_policy_value 值

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

    这些 值是可以给出的符号伪常量,而不是文字数值。它们必须作为字符串引用并且区分大小写。 "::xxx"

  • audit_log_policy_value

    该变量对应于 audit_log_policy系统变量的值。该值是一个无符号整数。 表 6.32 “audit_log_policy_value 值”显示了允许的值和相应的 audit_log_policy值。

    表 6.32 audit_log_policy_value 值

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

    这些 值是可以给出的符号伪常量,而不是文字数值。它们必须作为字符串引用并且区分大小写。 "::xxx"

  • audit_log_statement_policy_value

    该变量对应于 audit_log_statement_policy 系统变量的值。该值是一个无符号整数。 表 6.33,“audit_log_statement_policy_value 值” 显示了允许的值和相应的 audit_log_statement_policy 值。

    表 6.33 audit_log_statement_policy_value 值

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

    这些 值是可以给出的符号伪常量,而不是文字数值。它们必须作为字符串引用并且区分大小写。 "::xxx"

引用预定义函数

要在条件中引用预定义函数log ,请使用一个function项目,它采用 nameargs项目分别指定函数名称及其参数:

"function": {
  "name": "function_name",
  "args": arguments
}

name项目应仅指定函数名称,不带括号或参数列表。

args项目必须满足以下条件:

  • 如果函数没有参数, args则不应给出任何项目。

  • 如果函数确实接受参数, args则需要一个项目,并且参数必须按照函数描述中列出的顺序给出。参数可以引用预定义的变量、事件字段或字符串或数字常量。

如果参数数量不正确或参数不是函数所需的正确数据类型,则会发生错误。

例子:

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

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

以下列表描述了function项目允许的预定义功能:

  • audit_log_exclude_accounts_is_null()

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

    参数:

    没有任何。

  • audit_log_include_accounts_is_null()

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

    参数:

    没有任何。

  • debug_sleep(millisec)

    睡眠给定的毫秒数。该函数在性能测量期间使用。

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

    参数:

    • millisec:一个无符号整数,指定休眠的毫秒数。

  • find_in_exclude_list(account)

    Checks whether an account string exists in the audit log exclude list (the value of the audit_log_exclude_accounts system variable).

    Arguments:

    • account: A string that specifies the user account name.

  • find_in_include_list(account)

    Checks whether an account string exists in the audit log include list (the value of the audit_log_include_accounts system variable).

    Arguments:

    • account: A string that specifies the user account name.

  • string_find(text, substr)

    Checks whether the substr value is contained in the text value. This search is case-sensitive.

    Arguments:

    • text: The text string to search.

    • substr: The substring to search for in text.

Replacing a User Filter

In some cases, the filter definition can be changed dynamically. To do this, define a filter configuration within an existing filter. For example:

{
  "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" } }
            ]
          }
        }
      }
    }
  }
}

A new filter is activated when the activate item within a subfilter evaluates to true. Using activate in a top-level filter is not permitted.

A new filter can be replaced with the original one by using a ref item inside the subfilter to refer to the original filter id.

The filter shown operates like this:

  • The main filter waits for table_access events, either update or delete.

  • If the update or delete table_access event occurs on the temp_1 or temp_2 table, the filter is replaced with the internal one (without an id, since there is no need to refer to it explicitly).

  • If the end of the command is signalled (general / status event), an entry is written to the audit log file and the filter is replaced with the main filter.

The filter is useful to log statements that update or delete anything from the temp_1 or temp_2 tables, such as this one:

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

该语句生成多个 table_access事件,但审计日志文件仅包含generalstatus条目。

笔记

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