重複欄位
在 Unified Data Model (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.16all $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」 | 「主機」 |
| event_copy_2 | "192.0.2.2" | "host" |
| event_copy_3 | 「192.0.2.3」 | 「主機」 |
如果任何事件副本滿足重複欄位中所有未修改的條件,則該事件整體滿足所有條件。因此,如果重複欄位有多個條件,單一事件副本必須滿足所有條件。下列查詢範例會使用上述範例資料集,示範這項行為。
範例:未修改的運算式
對 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 | any $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 是事件副本編號。如果預留位置用於比對區段,可能會導致多個比對結果。
範例:重複欄位預留位置
以下範例會產生一個相符項目。`$ip` 預留位置等於 `event_copy_1` 的 `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 比賽變數值都不同。每個比對結果都有相同的事件範例:單一元素 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」 | 「主機」 | 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 |
|---|---|---|
| 「主機」 | ["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] = ""如果元素少於 1000 個,則會評估為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 專業人員尋求解答。