אוטומציה של איתור סודות ב-Git עם GitLeaks ו-TruffleHog

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

היכולות שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    776
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1022
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113

איתור סודות: היכן מפתחות דולפים למאגר

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

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

היסטוריה היא נקודת הדליפה המוזנחת ביותר. מחיקת שורה בקומיט חדש אינה מוחקת אותה מהקומיטים הקודמים: git log -p או שיבוט רגיל שולפים את הערך הישן תוך שניות, כולל ענפים ושכפולים נשכחים. התשובה האמינה היחידה — להתייחס למפתח כאל חשוף ולבטל אותו, ולא לקוות לשכתוב ההיסטוריה.

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

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

מה נותן חיפוש סודות: אפקט מדיד וסוגי כשלים

סקירה ידנית מוצאת סוד רק אם הבודק קורא במכוון שורות עם מפתחות בשינויי קבצים — בפועל כך נתפסים מקרים בודדים. חיפוש סודות אוטומטי מזיז את נקודת הגילוי שמאלה: הבדיקה רצה על כל קומיט וחוסמת מיזוג לפני שהמפתח הגיע לענף הראשי. שיעור הממצאים שנסגרים לפני מיזוג עולה מאחוזים בודדים ל-85–95% — הדליפה פשוט לא מגיעה לענף המשותף.

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

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

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

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

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

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

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

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

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

סדר היישום: ממיפוי מאגרים ועד מסירה

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

  1. מיפוי מאגרים. אוספים רשימה מהאחסון, מקו הבנייה וממראות מקומיות, מסמנים פעילים, ארכיוניים וחיצוניים, ולכל אחד מקבעים בעלים ורמת גישה.
  2. תעדוף. לפי הרכב ההיסטוריה ותדירות הקומיטים קובעים היכן נדרשת סריקה מלאה של ההיסטוריה והיכן די בבדיקת שינויים חדשים — זה הבדל של שעות עבודה.
  3. תרשים בקרה. בוחרים נקודות בדיקה: בדיקה לפני קומיט אצל המפתח, שלב בנייה, הרצה תקופתית לפי לוח זמנים. בפועל משלבים בדיקה מהירה בקומיט ובדיקה מלאה — בלילה.
  4. סף רגישות. מכווננים את הכללים כך שיסננו רעש ידוע מראש (דוגמאות מפתחות בתיעוד, מתקני בדיקה) ולא יפספסו דליפות אמיתיות. הסף נקבע לפי סוגי ממצאים, ולא לפי ערך גלובלי אחד — אחרת הצוות מתרגל להתעלם מהדוח.
  5. חריגים בכללים. מנסחים רשימה מפורשת עם סיבה ותוקף: חריגים קבועים הופכים במהרה לאזור עיוור, וממנו אחר כך דולף המפתח.
  6. בדיקה בזרימה. מריצים את השילוב של GitLeaks ו-TruffleHog על קומיטים אמיתיים, מודדים את שיעור החיובים השגויים ואת זמן הבדיקה, ומכווננים את הסף לרמה מקובלת.
  7. מסירה לצוות. מוסרים נוהל תגובה לממצא, סדר ביטול מפתח חשוף ורוטציה של אחראים.

כל שלב מסתיים בארטיפקט — רשימה, כלל או נוהל, ולכן התוצאה אינה תלויה במהנדס מסוים.

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

עבודה על אוטומציה של חיפוש סודות אינה מסתיימת בסורק מורץ, אלא בחבילת ארטיפקטים שלפיהם הצוות ממשיך להתנהל בעצמו.

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

  • סט כללים — תבניות שמתאימות לסטאק שלנו, ספי רגישות ותיאורי פורמטים של מפתחות, מסודרים לפי קטגוריות: עדכון של קבוצה אחת לא שובר את האחרות.
  • מדיניות חריגים — מרשם של נתיבים וקבצים שאינם נבדקים (נתוני בדיקה, דוגמאות קונפיגורציה), עם נימוק, בעלים ותאריך סקירה לכל רשומה.
  • תרשים בקרה — שלושה קווים: בדיקה במחשב המפתח לפני קומיט, בדיקה חוסמת בעת מיזוג ענפים, מעבר לילי על כל היסטוריית המאגר.
  • נוהל רוטציה — סדר פעולות בעת התראה: מי מבטל את המפתח, באיזה סדר, כיצד מאשרים שהגישה הישנה נסגרה, היכן מתעדים את האירוע.
  • הוראות לצוות — תזכיר בעמוד אחד: כיצד להריץ בדיקה מקומית, כיצד לכבות חיובי שגוי, למי לפנות במקרה של ממצא שנוי במחלוקת.
  • מטריצת אחריות — מי אחראי לכללים, מי מטפל בתור הממצאים, מי בודק את החריגים אחת לרבעון.

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

מקרה בוחן: כיצד חיפוש סודות סגר דליפות במאגר ישן

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

מה הראה מעבר מלא על ההיסטוריה

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

כשני שלישים מהממצאים ישבו בענפים מחוץ לקו הראשי — בבדיקה של שינויים חדשים בלבד הם לא היו צפים לעולם. עבדנו בשילוב של גלאים: כללים לפורמטים של המפתחות שלנו בתוספת TruffleHog לחיפוש לפי אנטרופיה.

מה השתנה בתהליך

את הבדיקה חילקנו לשלוש רמות: במחשב המפתח לפני שליחת שינויים, חובה בשרת הבנייה ומעבר קבוע על כל ההיסטוריה עם דוח. רשימת החריגים לדמויות בדיקה מנוהלת במפורש — בלי זה שטף של חיובים שגויים הורג את האמון בבדיקה; אצלנו שיעורם ירד מכ-70% ל-8%. את מה שנמצא לא רק מחקנו: כל מפתח בוטל והוחלף, כי סוד שנכנס להיסטוריה נחשב לחשוף.

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

במה שונה חיפוש לפי היסטוריית Git מבדיקת קומיטים חדשים?

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

מעבר חד-פעמי פותר משימה אחרת. הוא עובר על כל האובייקטים במאגר: כל קומיט, כל הענפים, כולל נטושים, תגים וקבצים שנמחקו מעץ העבודה אך נותרו בהיסטוריית Git. במאגר עם היסטוריה ארוכה אלה אלפי אובייקטים ודקות עבודה במקום שניות — אבל מוצאים את מה שבמצב הקוד הנוכחי לא נראה שנים.

עומק הבדיקה — ההבדל המרכזי בין המצבים. בקרת זרימה מנתחת את ההבדל בין מצבים, מעבר חד-פעמי מפרק כל תמונת מצב של העץ, ולכן תופס סוד שנוסף ונמחק עשרה קומיטים אחורה. בנפרד מתחשבים בהיסטוריה שנכתבה מחדש ובענפים שלא ביקרו בהם מזמן: ממצאים שם שורדים כל עריכה של עותק העבודה.

המסקנה המרכזית: מעבר חד-פעמי בעצמו אינו מתקן דבר. מחיקת קובץ וניקוי היסטוריה אינם מבטלים מפתח — עותקים כבר התפזרו בין שיבוטים, בניות ושכפולים. לכן התוצאה שלו אינה רשימת שורות אלא תכנית החלפת מפתחות: מפתח חשוף מבוטל, מונפק חדש, ורק אחר כך יש טעם לנקות את ההיסטוריה.

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

חיובים שגויים, עקיפת בדיקות וענפים ישנים

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

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

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

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

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

כיצד להבדיל בין נתוני בדיקה לאמיתיים?

לפי ההקשר: נתיב הקובץ, שם המשתנה, הסביבה, השורות הסמוכות, פורמט הערך. דוגמה מהתיעוד אינה מעוררת דאגה, ואילו טוקן עבודה בקוד — כן, ולכן הטיפול נעשה לפי עדיפויות ולא ברשימה רציפה.

מה לעשות עם ענפים נטושים?

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

נדבר על המשימה: מה נדרש מצדכם כדי להתחיל

כדי לחזור עם הערכה ותכנית יישום, ולא עם שאלות הבהרה בעוד שבוע, נדרש סט מינימלי של נתונים ראשוניים. לא נדרש דבר מעבר לכך בהתחלה — את השאר נשלים תוך כדי, כשנראה כיצד בנוי צינור איתור הסודות שלכם.

  • רשימת מאגרים וקבוצות: היכן חי הקוד, מה הועבר לארכיון, אילו פרויקטים ביודעין משאירים מחוץ לכיסוי — מכך תלוי היקף ההרצה הראשונית.
  • גישות לקריאה בלבד: חשבון שירות בפלטפורמת Git או טוקן אישי עם תוקף מוגבל ולוג הנפקות.
  • נקודת השתלבות: באיזה שלב מחברים את הבדיקה — לפני מיזוג, בבנייה לילית או כמשימה נפרדת לפי לוח זמנים.
  • אחראי אבטחה: אדם שמטפל בהתראות ומחזיק במטריצת הסלמה.
  • נוהל תגובה: מה נחשב קריטי, למי נשלחת התראה, כמה זמן מוקצב לביטול ולהנפקה מחדש של מפתח.
  • גישה למאגר הסודות: כדי שאפשר יהיה לבצע רוטציה לערך שנמצא, ולא רק לסמן אותו כממצא.
  • מדיניות לגבי היסטוריית קומיטים: אילו ענפים מותר לשכתב ואילו אסור לגעת בהם — אחרת קו הבסיס יציג אלפי שורות שכבר אינן רלוונטיות.
  • מצב עבודה וחלונות זמן: מתי אפשר להריץ מעברים כבדים ומי נשאר זמין.

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