重複欄位
在整合式資料模型 (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」 | 「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 | 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」 | 「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] = ""如果元素少於 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 專業人員尋求答案。