重复字段
在统一数据模型 (UDM) 中,某些字段被标记为重复,这表示它们是值列表或其他类型的消息。本文档介绍了如何针对重复的 UDM 字段使用表达式、占位符、数组索引和重复的消息。
布尔值表达式和重复字段
经过修改和未修改的布尔表达式都可以对重复字段起作用。
请考虑以下活动:
event_original {
principal {
// ip is a repeated field
ip: [ "192.0.2.1", "192.0.2.2", "192.0.2.3" ]
hostname: "host"
}
}
修改后的表达式
在重复字段的表达式中使用 any 和 all 修饰符。
any- 如果重复字段的任何元素满足条件,则整个事件都满足条件。例如:event_original满足any $e.principal.ip = "192.0.2.1"event_original失败any $e.repeated_field.field_a = "9.9.9.9"
all- 如果重复字段的所有元素都满足条件,则整个事件都满足条件。例如:event_original满足net.ip_in_range_cidr(all $e.principal.ip, "192.0.2.0/8")event_original失败all $e.principal.ip = "192.0.2.2"
使用 any 或 all 编写条件时,请注意使用 not 来排除条件的含义可能与使用否定运算符不同。
例如:
not all $e.principal.ip = "192.168.12.16"会检查是否并非所有 IP 地址都与192.168.12.16匹配,这意味着查询会检查是否至少有一个 IP 地址与192.168.12.16不匹配all $e.principal.ip != "192.168.12.16"会检查是否所有 IP 地址都与192.168.12.16不匹配,这意味着查询会检查是否没有 IP 地址与192.168.12.16匹配
限制:
any和all运算符仅与重复字段(而非标量字段)兼容。any和all不能用于联接两个重复字段。例如,any $e1.principal.ip = $e2.principal.ip无效。- 引用列表表达式不支持
any和all运算符。
未修改的表达式
对于未修改的表达式,重复字段中的每个元素都是单独处理的。如果某个事件的重复字段包含 n 个元素,则系统会对该事件的 n 个副本应用查询,其中每个副本都包含重复字段中的一个元素。这些副本是临时性的,不会存储。
该规则适用于以下副本:
| 活动文案 | principal.ip | principal.hostname |
|---|---|---|
| event_copy_1 | "192.0.2.1" | “host” |
| event_copy_2 | “192.0.2.2” | “host” |
| event_copy_3 | “192.0.2.3” | “host” |
如果任何事件副本满足重复字段中的所有未修改的条件,则整个事件满足所有条件。因此,如果您对重复字段设置了多个条件,则单个事件副本必须满足所有这些条件。以下查询示例使用上述示例数据集来演示此行为。
示例:未修改的表达式
以下规则针对 event_original 示例数据集运行时会返回一个匹配项,因为 event_copy_1 满足所有事件谓词:
rule repeated_field_1 {
meta:
events:
net.ip_in_range_cidr($e.principal.ip, "192.0.2.0/8") // Checks if IP address matches 192.x.x.x
$e.principal.ip = "192.0.2.1"
condition:
$e
}
以下规则在针对 event_original 示例数据集运行时不会返回匹配项,因为 $e.principal.ip 中没有满足所有事件谓词的事件副本。
rule repeated_field_2 {
meta:
events:
$e.principal.ip = "192.0.2.1"
$e.principal.ip = "192.0.2.2"
condition:
$e
}
对重复字段的修改后表达式与对重复字段的未修改表达式兼容,因为每个事件副本的元素列表都相同。请考虑以下规则:
rule repeated_field_3 {
meta:
events:
any $e.principal.ip = "192.0.2.1"
$e.principal.ip = "192.0.2.3"
condition:
$e
}
该规则适用于以下副本:
| 活动文案 | principal.ip | 任何 $e.principal.ip |
|---|---|---|
| event_copy_1 | "192.0.2.1" | ["192.0.2.1", "192.0.2.2", "192.0.2.3"] |
| event_copy_2 | “192.0.2.2” | ["192.0.2.1", "192.0.2.2", "192.0.2.3"] |
| event_copy_3 | “192.0.2.3” | ["192.0.2.1", "192.0.2.2", "192.0.2.3"] |
在这种情况下,所有副本都满足 any $e.principal.ip = "192.0.2.1",但只有 event_copy_3 满足 $e.principal.ip = "192.0.2.3"。这样一来,整个活动就会匹配。
我们还可以从以下角度来理解这些表达式类型:
- 使用
any或all的重复字段的表达式在event_original中的列表上运行。 - 不使用
any或all的重复字段表达式针对的是各个event_copy_n事件。
占位符和重复字段
重复字段可与占位变量分配搭配使用。与重复字段上未修改的表达式类似,系统会为每个元素创建一个事件副本。以 event_copy 为例,占位符会获取 event_copy_n 的重复字段值,其中 n 是事件副本编号。如果在匹配部分中使用占位符,则可能会导致多个匹配项。
示例:重复字段占位符
以下示例生成一个匹配项。对于 `event_copy_1`,`$ip` 占位符等于 `192.0.2.1`,满足规则中的谓词。 匹配的事件样本包含单个元素 `event_original`。
// Generates 1 match.
rule repeated_field_placeholder1 {
meta:
events:
$ip = $e.principal.ip
$ip = "192.0.2.1"
$host = $e.principal.hostname
match:
$host over 5m
condition:
$e
}
以下示例会生成三个匹配项。$ip 占位符等于不同值,对应于每个不同的 event_copy_n 副本。由于 $ip 位于匹配部分,因此分组是基于 $ip 完成的。因此,您会获得三个匹配项,每个匹配项的 $ip 匹配变量的值都不同。每个匹配项都具有相同的事件样本:单个元素 event_original。
// Generates 3 matches.
rule repeated_field_placeholder2 {
meta:
events:
$ip = $e.principal.ip
net.ip_in_range_cidr($ip, "192.0.2.0/8") // Checks if IP matches 192.x.x.x
match:
$ip over 5m
condition:
$e
}
使用分配给重复字段的占位变量时的结果
占位符会分配给每个重复字段的每个元素,而不是整个列表。当它们在 outcome 部分中使用时,系统仅使用满足前面部分条件的元素来计算结果。
请考虑以下规则:
rule outcome_repeated_field_placeholder {
meta:
events:
$ip = $e.principal.ip
$ip = "192.0.2.1" or $ip = "192.0.2.2"
$host = $e.principal.hostname
match:
$host over 5m
outcome:
$o = array_distinct($ip)
condition:
$e
}
此规则的执行分为四个阶段。第一阶段是事件复制:
| 活动文案 | $ip | $host | $e |
|---|---|---|---|
| event_copy_1 | "192.0.2.1" | “host” | event_id |
| event_copy_2 | “192.0.2.2” | “host” | event_id |
| event_copy_3 | “192.0.2.3” | “host” | event_id |
然后,事件部分将过滤掉与过滤条件不匹配的行:
| 活动文案 | $ip | $host | $e |
|---|---|---|---|
| event_copy_1 | "192.0.2.1" | “host” | event_id |
| event_copy_2 | “192.0.2.2” | “host” | event_id |
event_copy_3 已被滤除,因为 "192.0.2.3" 不满足 $ip = "192.0.2.1" or $ip = "192.0.2.2"。
然后,match 部分将按匹配变量进行分组,outcome 部分将对每个组执行聚合:
| $host | $o | $e |
|---|---|---|
| “host” | ["192.0.2.1", "192.0.2.2"] | event_id |
$o = array_distinct($ip) 是使用上一阶段(而非事件复制阶段)的 $ip 计算得出的。
最后,condition 部分将过滤每个组。由于此规则仅检查是否存在 $e,因此之前的行将产生一次检测。
$o 不包含 $e.principal.ip 中的所有元素,因为并非所有元素都满足了“事件”部分中的所有条件。不过,由于事件样本使用 event_original,因此 e.principal.ip 的所有元素都会显示在事件样本中。
数组索引
您可以对重复字段执行数组索引。如需访问第 n 个重复字段元素,请使用标准列表语法(元素从 0 开始编制索引)。超出范围的元素会返回默认值。
$e.principal.ip[0] = "192.168.12.16"$e.principal.ip[999] = ""如果元素少于 1, 000 个,则计算结果为true。
限制:
- 索引必须是非负整数字面量。例如,
$e.principal.ip[-1]无效。 - 具有
int类型的价值(例如,设置为int的占位符)不计入。 - 数组索引不能与
any或all结合使用。例如,any $e.intermediary.ip[0]无效。 - 数组索引不能与映射语法结合使用。例如,
$e.additional.fields[0]["key"]无效。 - 如果字段路径包含多个重复字段,则所有重复字段都必须使用数组索引。例如,
$e.intermediary.ip[0]无效,因为intermediary和ip都是重复字段,但只有ip有索引。
重复消息
当 message 字段重复时,会产生意外效果,即降低匹配的可能性。以下示例对此进行了说明。
请考虑以下活动:
event_repeated_message {
// about is a repeated message field.
about {
// ip is a repeated string field.
ip: [ "192.0.2.1", "192.0.2.2", "192.0.2.3" ]
hostname: "alice"
}
about {
hostname: "bob"
}
}
如上文针对重复字段中未修改的表达式所述,系统会为重复字段的每个元素创建一个临时事件副本。请考虑以下规则:
rule repeated_message_1 {
meta:
events:
$e.about.ip = "192.0.2.1"
$e.about.hostname = "bob"
condition:
$e
}
该规则适用于以下副本:
| 活动文案 | about.ip | about.hostname |
|---|---|---|
| event_copy_1 | "192.0.2.1" | "alice" |
| event_copy_2 | “192.0.2.2” | "alice" |
| event_copy_3 | “192.0.2.3” | "alice" |
| event_copy_4 | "" | "bob" |
该事件与规则不匹配,因为不存在满足所有表达式的事件副本。
重复消息和数组索引
在重复消息字段上使用未修改的表达式进行数组索引时,可能会出现另一种意外行为。请参考以下使用数组索引的规则示例:
rule repeated_message_2 {
meta:
events:
$e.about.ip = "192.0.2.1"
$e.about[1].hostname = "bob"
condition:
$e
}
相应规则会应用于以下副本:
| 活动文案 | about.ip | about[1].hostname |
|---|---|---|
| event_copy_1 | "192.0.2.1" | "bob" |
| event_copy_2 | “192.0.2.2” | "bob" |
| event_copy_3 | “192.0.2.3” | "bob" |
| event_copy_4 | "" | "bob" |
由于 event_copy_1 满足 repeated_message_2 中的所有表达式,因此该事件与规则匹配。
这可能会导致意外行为,因为规则 repeated_message_1 缺少数组索引,因此未生成匹配项,而规则 repeated_message_2 使用了数组索引,因此生成了匹配项。
需要更多帮助?获得社区成员和 Google SecOps 专业人士的解答。