החלת לוגיקת חלונות YARA-L 2.0
המדריך הזה עוזר למהנדסי אבטחה לבחור את סוג החלון הנכון לשאילתות כדי להימנע משגיאות קומפיילר מסוג 'המשתנה לא מוגבל'. המעבר מחלונות נעים לחלונות מתגלגלים מאפשר לכם לבנות לוגיקה שתלויה בהיעדר אירועים, כמו דופק חסר או מקור יומן שנכשל.
לפני שמתחילים
מוודאים שיש לחשבון שלכם אחד מהתפקידים הבאים כדי ליצור ולשנות שאילתות YARA-L:
- אדמין של מנוע הזיהוי (
roles/chronicle.detectionEngineAdmin) - עריכה ב-SecOps (
roles/chronicle.editor)
סוגי חלונות נתמכים
ב-YARA-L 2.0 יש התנהגויות שונות של חלונות שמשמשות לקביעה של חלוקת הזמן ושל אופן הקיבוץ של האירועים. אפשר לקבץ שדות של אירועים ומשתני מיקום בקטע match לפי גרנולריות זמן שצוינה, באמצעות חלונות נתמכים:
| סוג החלון הנתמך | תחביר | תיאור | תרחיש נפוץ לדוגמה |
|---|---|---|---|
| Hop | $key over <duration> |
יוצרת מרווחי זמן קבועים וחופפים. המערכת מגדירה את החפיפה וההתאמה כדי לזהות אירועים שקרו קרוב לגבולות. | קורלציה כללית של כמה אירועים, ללא קשר לשעות ההתחלה המדויקות. |
| Tumbling | $key by <duration> |
מפלח את הנתונים לבלוקים רציפים בגודל קבוע שלא חופפים זה לזה. ההערכה מתבצעת ללא קשר להגעת האירוע. | כימות פעילות במשבצות זמן קבועות (לדוגמה, $user by 30m) או זיהוי היעדר אירועים. |
| הזזה | $key over <duration> [before|after] $pivot |
החלון מוצמד לאירוע ספציפי "pivot". כדי להפעיל חיפוש אחורה או קדימה, צריך שיהיה ציר זמן. |
רצף קפדני שבו סדר האירועים הוא קריטי (לדוגמה, File Download after Login). |
הסבר על הלוגיקה של window_start ו-window_end
צוות Google Security Operations מספק שתי מילות מפתח אוניברסליות שמורות, שמובילות ישירות לחותמות זמן של GoogleSQL לשימוש בשאילתות. מילות המפתח האלה מאפשרות לכם לגשת לגבולות של משבצות הזמן:
-
window_start: הגבול ההתחלתי של משבצת הזמן. -
window_end: הגבול הסוגר של משבצת הזמן.
מגבלות שימוש
- דרישות ההתאמה: כדי להשתמש במילות המפתח האלה, צריך להגדיר חלון (
byאוover) בקטעmatch. - הגבלת קטע: אפשר להשתמש במילות המפתח האלה ב-
condition, ב-orderאו ב-outcome. הם לא חוקיים בקטעevents. - מרחב שמות: אל תשתמשו בשמות האלה כשמות של משתנים מותאמים אישית (לדוגמה,
$window_start).
קביעת סוג החלון והתחביר
אפשר להשתמש בטבלה הזו כהפניה מהירה כדי להבין באיזה סוג חלון ובאיזו תחביר צריך להשתמש בכללי הזיהוי.
| תרחיש | חלון הזמן המומלץ | מילות מפתח מומלצות | יתרון מרכזי |
|---|---|---|---|
| זיהויים בתדירות גבוהה (לדוגמה, מתקפות Brute Force) | חלון הזזה (over) |
window_start, window_end |
מופעל באופן מיידי כשמגיעים לסף בתקופה מתגלגלת. |
| Absence/non-existence (לדוגמה, missing heartbeats) | חלון מתגלגל (by) |
window_start, window_end |
הפונקציה מעריכה בלוקים קבועים של זמן גם אם לא מתרחשים אירועים, וכך מונעת שגיאות מסוג Variable Not Bounded. |
| דיווח כרונולוגי | החלקה או נפילה | order: window_start asc |
הפלט של ההתראות עובר סטנדרטיזציה כדי שיהיה קל יותר לנתח את ציר הזמן בממשק המשתמש של Chronicle. |
| סינון לפי תקופת זמן | החלקה או נפילה | condition: window_start > "2026-01-01 00:00:00Z" |
ההערכה של כלל ההגבלות מוגבלת לתאריכים ספציפיים באמצעות המרת חותמת זמן ב-GoogleSQL. |
השוואה בין סוגים של חותמות זמן ואזורי זמן
ב-YARA-L יש תמיכה בהשוואה ישירה בין window_start לבין window_end עם מחרוזות בפורמט חותמת זמן של GoogleSQL. כך אפשר לבצע סינון מדויק בלי להגדיר המרה ידנית של טיפוסים.
הערה: תמיד צריך לציין UTC באמצעות הסיומת Z (לדוגמה, "2026-03-17T17:35:00Z") כדי להתאים לחותמות הזמן של אירועים ב-UDM.
שימוש במסננים של חותמות זמן לביצועים. אם אתם רוצים רק לוודא שאירוע אחד קרה אחרי אירוע אחר, בדרך כלל יעיל יותר להשוות את חותמות הזמן בקטע condition: $e1.metadata.event_timestamp.seconds < $e2.metadata.event_timestamp.seconds.
מידע נוסף על התחביר של קטע match ועל התחביר של קטע condition
דוגמאות: window_end ו-window_start
-
window_end < "2026-01-01T12:30:00Z"(תאריך, שעה והסיומת UTC) -
window_start != "2026-01-01 15:00:00+00"(עם קיזוז ל-UTC)
אם ההשוואה נכשלת, צריך לוודא שהמחרוזת היא בפורמט חותמת הזמן הקנוני של GoogleSQL.
חלונות Hop
חלון קפיצה יוצר מרווחי זמן חופפים כדי שלא יוחמצו אירועים שמתרחשים ליד הגבולות של חלון.
- תרחיש שימוש: הכי מתאים לזיהויים שבהם צריך לתפוס תרחיש ספציפי בלי קשר לנקודת ההתחלה או הסיום המדויקת של מרווח החלון.
- תמיכה: נתמך לצורך צבירה בחיפוש ובמרכזי בקרה.
שאילתות YARA-L עם קטע match משתמשות בחלונות קפיצה כדי ליצור קורלציה בין כמה אירועים לאורך זמן. המערכת מחלקת את טווח הזמן של הרצת השאילתה לקבוצה של חלונות קפיצה קבועים וחופפים. אתם מציינים את משך הזמן של החלונות האלה בקטע match, אבל המערכת מגדירה את חלון החפיפה ואת התאמת החלונות. לאחר מכן, האירועים עוברים קורלציה בכל אחד מחלונות הזמן שנקבעו מראש.
מידע נוסף על התחביר של קטע match
לחלונות של קפיצות יש השלכות ספציפיות על זיהויים של כללים מורכבים. מידע נוסף זמין במאמר בנושא כללים מורכבים: מרווחי זמן וחלונות של קפיצות.
דוגמה: חלונות חפיפה של קפיצות לביצוע קורלציה רציפה
בדוגמה הבאה מוצגת שאילתה שמופעלת על טווח הזמן [1:00, 2:00], עם קטע match $user over 30m. קבוצה אפשרית של חלונות חופפים שהמערכת יוצרת היא [1:00, 1:30], [1:03, 1:33] ו-[1:06, 1:36].
כלל
rule hop_window_brute_force_example {
meta:
description = "Detects multiple failed logins within a shifting 30-minute window."
severity = "Medium"
events:
$login.metadata.event_type = "USER_LOGIN"
$login.extensions.auth.auth_status = "FAILURE"
$login.principal.user.userid = $user
match:
// This creates the overlapping windows (e.g., 1:00-1:30, 1:03-1:33)
$user over 30m
condition:
// This will trigger if 10 or more failures fall into any single 30m hop
#login >= 10
}
לחפש
metadata.event_type = "USER_LOGIN"
security_result.action = "FAIL"
principal.user.userid = $user
match:
// This creates the overlapping windows (e.g., 1:00-1:30, 1:03-1:33)
$user over 30m
```
מרכז שליטה
metadata.event_type = "USER_LOGIN"
security_result.action = "FAIL"
principal.user.userid = $user
match:
// This creates the overlapping windows (e.g., 1:00-1:30, 1:03-1:33)
$user over 30m
דוגמה: קורלציה של כמה אירועים באמצעות חלון קפיצה
בדוגמה הבאה מתועדים אירועים שמתרחשים באותו פרק זמן כללי:
כלל
rule hop_window_example {
meta:
description = "Detect a user with a failed login followed by a success within 30m"
events:
// Event 1: Capture failed login attempts
$fail.metadata.event_type = "USER_LOGIN"
$fail.security_result.action = "FAIL"
$fail.principal.user.userid = $user
// Event 2: Capture successful login attempts
$success.metadata.event_type = "USER_LOGIN"
$success.security_result.action = "ALLOW"
$success.principal.user.userid = $user
match:
// Correlate events for the SAME $user within a rolling 30-minute window.
$user over 30m
condition:
// Ensure both a failed ($fail) and a successful ($success) login event occurred for the same user within the 30m window.
$fail and $success
}
לחפש
// Event 1: Capture failed login attempts
metadata.event_type = "USER_LOGIN"
security_result.action = "FAIL"
principal.user.userid = $user // Assign user ID to a placeholder
// Event 2: Capture successful login attempts
metadata.event_type = "USER_LOGIN"
security_result.action = "ALLOW"
principal.user.userid = $user // Link to the same user placeholder
match:
// Correlate events for the SAME $user within a rolling 30-minute window.
$user over 30m
מרכז שליטה
// Event 1: Capture failed login attempts
metadata.event_type = "USER_LOGIN"
security_result.action = "FAIL"
principal.user.userid = $user // Assign user ID to a placeholder
// Event 2: Capture successful login attempts
metadata.event_type = "USER_LOGIN"
security_result.action = "ALLOW"
principal.user.userid = $user // Link to the same user placeholder
match:
// Correlate events for the SAME $user within a rolling 30-minute window.
$user over 30m
דוגמה: השוואה של חלונות קפיצה
כדי לזהות ניסיון של מתקפת כוח ברוטלי, 10m חלון מקבץ את כל הכשלים USER_LOGIN. לאחר מכן, התנאי בודק אם הספירה (#e) בטווח הספציפי של 10 דקות חורגת מהסף שהגדרתם.
כלל
rule failed_logins
{
meta:
author = "Security Team"
description = "Detects multiple failed user logins within 10-minute windows."
severity = "HIGH"
events:
$e.metadata.event_type = "USER_LOGIN"
$e.security_result.action = "FAIL"
$user = $e.target.user.userid
match:
$user over 10m
condition:
#e >= 5
}
לחפש
metadata.event_type = "USER_LOGIN"
security_result.action = "FAIL"
$user = target.user.userid
match:
$user over 10m
מרכז שליטה
metadata.event_type = "USER_LOGIN"
security_result.action = "FAIL"
$user = target.user.userid
match:
$user over 10m
חלונות מתגלגלים
הערה: התכונה הזו לא זמינה לכל הלקוחות בכל האזורים.
חלון מתגלגל מפלח את הנתונים למרווחי זמן רציפים, לא חופפים ובעלי גודל קבוע. חותמת הזמן של כל אירוע נכללת בחלון אחד בלבד. אין חפיפה בין חלונות מתגלגלים. לעומת זאת, חלון קופץ או חלון הזזה יכולים לכלול מרווחי זמן חופפים.
כדי להטמיע חלון עוקב (tumbling window), משתמשים באופרטור by בקטע match. חלונות מתגלגלים מחלקים את הזמן לבלוקים רציפים שמוצבים זה לצד זה, למשל:
-
by 1h: יוצר חלונות לכל שעה (לדוגמה,[00:00:00-00:59:59], [01:00:00-01:59:59]). -
by 10m: יוצר חלונות לכל פרק זמן של 10 דקות (לדוגמה,[00:00:00-00:09:59],[00:10:00-00:19:59]).
תרחישים נפוצים לדוגמה
כדאי להשתמש בחלונות נעים כשצריך:
- ניתוח אירועים בפרקי זמן נפרדים שלא חופפים.
- המערכת תפיק רק זיהוי אחד לישות נתונה (כפי שמוגדר על ידי משתני ההתאמה) בכל מרווח זמן קבוע, בלי קשר למספר הפעמים שהאירוע מתרחש.
- ספירת ישויות ייחודיות לאורך תקופות קבועות.
התנהגות של הסרת כפילויות
מאפיין מרכזי של חלונות מתגלגלים הוא האופן שבו המנוע מטפל בזיהויים בכל חלון עבור אותו סט של משתני התאמה:
- זיהוי אחד לכל חלון: עבור קבוצה נתונה של ערכים של משתני ההתאמה (לדוגמה,
$useridספציפי), המנוע יוצר לכל היותר זיהוי אחד לכל חלון עוקב (tumbling window). - האירוע הראשון שהגיע הוא זה שקובע: האירועים הראשונים שנקלטים ועומדים בתנאי הכלל עבור קבוצת משתני ההתאמה הזו בתוך חלון זמן ספציפי מפעילים את הזיהוי.
- ביטול כפילויות: אירועים נוספים שתואמים לקריטריונים באותו מופע של חלון לא ייצרו זיהויים נוספים.
תחביר
התחביר בקטע match הוא: match: $variable by <duration>
-
$variableהוא משתנה ה-placeholder שאתם מחפשים התאמה שלו. -
durationהוא מספר שאחריו יחידת זמן:m(דקה),h(שעה),d(יום). - צריך לציין זמן מינימלי של דקה אחת וזמן מקסימלי של 72 שעות או שלושה ימים.
דוגמה: קיבוץ במרווחי זמן קבועים
קבוצת הכללים הבאה מתעדת כניסות לפי $userid בחלונות של שעה אחת שלא חופפים.
כלל
rule TumblingWindowExample {
meta:
description = "Example using a 1-hour tumbling window"
events:
$e.metadata.event_type = "USER_LOGIN"
$e.principal.user.userid = $userid
match:
$userid by 1h
condition:
$e
}
לחפש
metadata.event_type = "USER_LOGIN"
principal.user.userid = $userid
match:
$userid by 1h
מרכז שליטה
metadata.event_type = "USER_LOGIN"
principal.user.userid = $userid
match:
$userid by 1h
דוגמה: התנהגות זיהוי (משתמש = "Alex")
- אירוע 1: אלכס מתחבר בשעה 00:30. היא נכללת בחלון
[00:00:00-00:59:59]. המנוע יוצר זיהוי של אלכס בחלון הזה. - אירוע 2: משתמש אחר, 'טיילור', מתחבר בשעה 00:45. ההגדרה הזו נכללת גם ב-
[00:00:00-00:59:59], אבל בגלל ש-$useridשונה, המנוע יוצר זיהוי נפרד עבור Taylor. - אירוע 3: אלכס נכנס שוב לחשבון בשעה 00:40. הפעולה הזו עדיין מתבצעת במסגרת חלון הזמן של
[00:00:00-00:59:59]. מכיוון שכבר קיימת זיהוי של אלכס, האירוע הזה מוסר ככפילות. לא נוצר זיהוי חדש. - אירוע 4: אלכס מתחבר בשעה 01:20. הוא יופיע בחלון הבא,
[01:00:00-01:59:59]. המנוע יוצר זיהוי חדש עבור אלכס.
למרות שהאירוע הראשון והאירוע הרביעי של אלכס התרחשו בהפרש של פחות משעה, הם נכללים בזיהויים נפרדים כי האירוע הרביעי חוצה את הגבול של החלון הקבוע.
הגדרת חלונות מתגלגלים לזיהוי היעדרות
כדי לקבל התראה על ספירה של אפס ולמנוע כשלים בהידור, מבצעים את השלבים הבאים:
- מזהים את יעד הזיהוי. קובעים אם מחפשים תדירות גבוהה או חוסר פעילות.
- בוחרים את
windowמילת המפתח. משתמשים ב-overכדי לציין תדירות וב-byכדי לציין היעדר. - גבולות חלון ההפניה. משתמשים במילות המפתח
window_startו-window_endכדי להפנות לגבולות ספציפיים של משבצת הזמן.
הקשר: משתמשים ב-outcome: $ext_window_end = window_end כדי לכלול במטא-נתונים של ההתראה את שעת הסיום המדויקת של פעימת הלב שהוחמצה.
דוגמה: זיהוי פעימת לב חסרה באמצעות מטא-נתונים
חלונות מתגלגלים מאפשרים לכם להגדיר התראה על ספירה של אפס, וכך להימנע מכשלים בהידור כשמחפשים חוסר פעילות.
כלל
rule missing_heartbeat_detection {
meta:
description = "Alert when a system fails to check in within a 24h block"
events:
$e.metadata.event_type = "STATUS_UPDATE"
$host = $e.principal.hostname
match:
$host by 24h // Tumbling window lets you detect zero counts
outcome:
$event_count = count($e.metadata.id)
$missing_window_start = window_start
$missing_window_end = window_end
condition:
$event_count = 0 and window_start > "2026-01-01T12:30:00Z"
}
לחפש
metadata.event_type = "STATUS_UPDATE"
$host = principal.hostname
match:
$host by 24h // Tumbling window lets you detect zero counts
outcome:
$event_count = count(metadata.id)
$missing_window_start = window_start
$missing_window_end = window_end
מרכז שליטה
metadata.event_type = "STATUS_UPDATE"
$host = principal.hostname
match:
$host by 24h // Tumbling window lets you detect zero counts
outcome:
$event_count = count(metadata.id)
$missing_window_start = window_start
$missing_window_end = window_end
חלונות הזזה
חלון נע מעוגן לאירוע מרכזי ספציפי, והוא יכול להסתכל קדימה (after) או אחורה (before).
תרחישים נפוצים לדוגמה
משתמשים בחלונות נעים כשהרצף של האירועים הוא קריטי:
- רצף קפדני: זיהוי של שרשרת התקפות (לדוגמה,
e1מתרחש עד שתי דקות אחריe2). - תזמון יחסי: חיפוש אירוע שמתרחש בתוך היסט ספציפי של טריגר (לדוגמה,
Network Connectionתוך 30 שניות מ-Process Start). - זיהוי היעדרות: זיהוי מצב שבו אירוע חובה של 'ניקוי' או 'דופק' לא מתרחש אחרי אירוע התחלה.
תחביר
match: <grouping_keys> over <duration> [before|after] <$pivot_event>
| רכיב | תיאור | דוגמה |
|---|---|---|
| קיבוץ מפתחות | שדות נפוצים שמשמשים לקישור בין אירועים. | $host, $user |
| משך הזמן | הזמן שחלף מאירוע הציר. | 5m, 1h, 30s |
| כיוון | האם החלון מתרחב קדימה או אחורה. | after, before |
| אירוע מרכזי | משתנה האירוע שקובע את נקודת ההתחלה של החלון. | $proc, $alert |
דוגמאות לחלונות הזזה תקינים:
$var1, $var2 over 5m after $e1$user over 1h before $e2$host, $ip over 1h before $e2
דרישות ומגבלות
- ביצועים: חלונות נעים דורשים יותר כוח עיבוד מאשר חלונות קופצים. כדאי להשתמש בהם רק כשסדר האירועים נדרש באופן מוחלט (לדוגמה, כשאירוע אחד חייב להתרחש תוך חמש דקות אחרי אירוע אחר).
- שאילתות של אירוע יחיד: אל תשתמשו בחלונות נעים ללוגיקה של אירוע יחיד. במקום זאת, אפשר להשתמש בכמה משתני אירועים בקטע
condition.
דוגמה: קורלציה צופה פני עתיד (after)
כלל
rule sliding_window_after_example {
meta:
description = "Detect a network connection occurring within 1 minute after a suspicious process launch."
severity = "High"
events:
$proc.metadata.event_type = "PROCESS_LAUNCH"
$proc.principal.hostname = $host
$net.metadata.event_type = "NETWORK_HTTP"
$net.principal.hostname = $host
match:
// $proc is the pivot; the 1-minute window starts at the $proc timestamp
$host over 1m after $proc
condition:
$proc and $net
}
לחפש
אין תמיכה ב-after בחיפוש.
מרכז שליטה
אין תמיכה ב-after במרכזי בקרה.
דוגמה: קורלציה רטרוספקטיבית (before)
אפשר להשתמש ב"before"חלון נע כדי לחקור פעילות שהובילה להתראה ספציפית. השימוש הזה נפוץ בניתוח שורש הבעיה, כדי לזהות מה קרה מיד לפני זיהוי קריטי.
כלל
rule sliding_window_before_example {
meta:
description = "Identify file modifications occurring in the 5 minutes before a ransomware alert."
severity = "Critical"
events:
$file.metadata.event_type = "FILE_MODIFICATION"
$file.principal.hostname = $host
$alert.metadata.event_type = "ANTIVIRUS_DETECTION"
$alert.metadata.product_name = "Premium_AV"
$alert.principal.hostname = $host
match:
// $alert is the pivot; the 5-minute window ends at the $alert timestamp
$host over 5m before $alert
condition:
$file and $alert
}
לחפש
אין תמיכה ב-before בחיפוש.
מרכז שליטה
אין תמיכה ב-before במרכזי בקרה.
פתרון בעיות
בקטע הזה מוסבר על השהיה, המגבלות והפתרונות לבעיות נפוצות שקשורות לחלונות ב-YARA-L.
זמן אחזור ומגבלות
כללים שמשתמשים בחלונות מתגלגלים (
by) מופעלים רק בסוף בלוק הזמן הקבוע. לדוגמה, כלל עםmatch: $user by 24hמוערך רק אחרי שחלף חלון הזמן של 24 שעות.השהיית התראות: כללים שמשתמשים ב-
by(חלון זמן מתגלגל) מופעלים רק אחרי שחלף חלון הזמן הקבוע. כללby 24hלא ישלח התראה באמצע החלון.חוסר התאמה בממשק המשתמש: בחיפוש ובמרכזי הבקרה, מילת המפתח
window_startמתייחסת ישירות לשדהTIME_BUCKET. כשמסננים או מקבצים לפיwindow_start, כותרת העמודה מוצגת כ-TIME_BUCKETבממשק המשתמש.זוהי מגבלה ידועה בתצוגת ממשק המשתמש, אבל הלוגיקה שלכם נשארת תקפה.
תיקון שגיאות
| קוד שגיאה | תיאור | תיקון |
|---|---|---|
| Variable Not Bounded | הכלל משתמש בover (חלון הזזה) עם תנאי $count = 0. |
משנים את מילת המפתח של חלון הזמן ל-by (חלון זמן מתגלגל). חלונות נעים דורשים אירוע קיים כדי לעגן את החלון, בעוד שחלונות מתגלגלים לא דורשים זאת. |
| UI Header Mismatch | במקום window_start, המשתמש רואה TIME_BUCKET בממשק המשתמש. |
לא נדרש תיקון. לוגיקת הסינון והסדר עדיין פועלת בצורה תקינה באמצעות מילות המפתח. |
מזהה לא מוכר: window_start |
מילת המפתח נמצאת בשימוש, אבל לא הוגדר חלון ב-match. |
מוסיפים הצהרה לגבי חלון הזמנים להצגת התוכן בקטע match (לדוגמה, $hostname by 1h). |
שימוש לא תקין ב-window_start באירועים |
מילת המפתח מוזכרת בקטע events. |
מעבירים את הלוגיקה לקטע condition או לקטע outcome. גבולות החלון מחושבים רק אחרי שקבוצת האירועים נמצאת בשלב ההתאמה. |
המאמרים הבאים
הבעיה עדיין לא נפתרה? קבלת תשובות מחברי הקהילה וממומחי Google SecOps.