החלת לוגיקת חלונות 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]. המנוע יוצר זיהוי חדש עבור אלכס.

למרות שהאירוע הראשון והאירוע הרביעי של אלכס התרחשו בהפרש של פחות משעה, הם נכללים בזיהויים נפרדים כי האירוע הרביעי חוצה את הגבול של החלון הקבוע.

הגדרת חלונות מתגלגלים לזיהוי היעדרות

כדי לקבל התראה על ספירה של אפס ולמנוע כשלים בהידור, מבצעים את השלבים הבאים:

  1. מזהים את יעד הזיהוי. קובעים אם מחפשים תדירות גבוהה או חוסר פעילות.
  2. בוחרים את windowמילת המפתח. משתמשים ב-over כדי לציין תדירות וב-by כדי לציין היעדר.
  3. גבולות חלון ההפניה. משתמשים במילות המפתח 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.