重复字段

支持的平台:

在统一数据模型 (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"
  }
}

修改后的表达式

在重复字段的表达式中使用 anyall 修饰符。

  • 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"

使用 anyall 编写条件时,请注意使用 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 匹配

限制:

  • anyall 运算符仅与重复字段(而非标量字段)兼容。
  • anyall 不能用于联接两个重复字段。例如,any $e1.principal.ip = $e2.principal.ip 无效。
  • 引用列表表达式不支持 anyall 运算符。

未修改的表达式

对于未修改的表达式,重复字段中的每个元素都是单独处理的。如果某个事件的重复字段包含 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"。这样一来,整个活动就会匹配。

我们还可以从以下角度来理解这些表达式类型:

  • 使用 anyall 的重复字段的表达式在 event_original 中的列表上运行。
  • 不使用 anyall 的重复字段表达式针对的是各个 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 的占位符)不计入。
  • 数组索引不能与 anyall 结合使用。例如,any $e.intermediary.ip[0] 无效。
  • 数组索引不能与映射语法结合使用。例如,$e.additional.fields[0]["key"] 无效。
  • 如果字段路径包含多个重复字段,则所有重复字段都必须使用数组索引。例如,$e.intermediary.ip[0] 无效,因为 intermediaryip 都是重复字段,但只有 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 专业人士的解答。