בפיתוח תוכנה אנו תלויים הן ברכיבים או בארטיפקטים שלנו והן ברכיבים של צד שלישי. ניהול תלויות גמיש חיוני לתוכנה מודרנית. מנהלי חבילות כמו NPM, Maven, פְּעִים or נוגט משמשים לעתים קרובות לציון תלויות תוכנה. כלים אלה תוכננו תוך מחשבה על נוחות וקלות שימוש, ולא על אבטחה.
הבעיה
הבעיה היא שגמישות וקלות שימוש עבור מפתחים מושכות את הרעים, הרואים בתלות בתוכנה קסם שאי אפשר לעמוד בפניו עבור העסק שלהם. התוצאה: גורמים רעים עקבו אחר כל נתיבי ההתקפה האפשריים המוצגים כאן. מקור: "אוסף הסכינים של תוכנת קוד פתוח: סקירה של התקפות שרשרת אספקה של תוכנה בקוד פתוח"
בפוסט זה נתמקד בשימוש בהצהרות גרסה פתוחות, במובן שהגרסה שהורדה אינה קבועה אלא חייבת להשתייך לטווח מסוים. בזמן הבנייה, הגרסה הקיימת הגבוהה ביותר התואמת לטווח הגרסאות שצוין נבחרת ומורדת/מותקנת על ידי מנהל החבילות.
בואו נמחיש הצהרות פתוחות בהצהרות תלויות עבור מנהלי חבילות שונים:
- NPM: package.json
{
...
"תלויות": {
...
"מקבל": ">=1.3.8",
"לודאש": "~4.16.0",
...
},
...
}
הגרסה הגדולה ביותר הקיימת, שאינה נמוכה מ-1.3.8, עבור חבילת accepts תותקן, כמו גם עדכון ה-'patch' הגדול ביותר עבור lodash בטווח 4.16.x.
- מייבן: pom.xml
...
...
commons-io
commons-io
לְשַׁחְרֵר
...
...
הגרסה האחרונה הזמינה עבור commons-io (קובץ jar) תתווסף כתלות.
- צִפצוּף: setup.py
...
להכין(
...
install_requires=['peppercorn', 'launchpadlib'],
...
)
...
לתכניות גרסה פתוחה כאלה יש צד טוב וצד רע. הטוב שבהן הוא שגרסאות חדשות יותר בְּדֶרֶך כְּלַל מכילים שיפורים פונקציונליים ואיכותיים, תיקוני באגים ותיקוני אבטחה, המשודרגים אוטומטית. שימו לב שעבור רוב הפרויקטים בעולם האמיתי, התיקונים אינם מועברים לגרסאות מינוריות קודמות, למעט אולי פגיעויות אבטחה קטסטרופליות. גרסאות פתוחות טובות גם לשימוש בספריות, כדי להפחית את מספר הגרסאות שיש להתקין לאחר פתרון כל התלויות.
אבל לטווחי גרסאות פתוחים יש גם צד שלילי. אי אפשר לדעת בדיוק אילו גרסאות יותקנו בזמן הבנייה, ומערכות בניה אינן ניתנות לחזרה. ויש גם אפל מצדד בגרסאות פתוחות. אם שחקן זדוני יצליח לפרסם רכיב זדוני במאגר הציבורי עם גרסה גבוהה התואמת לטווח הפתוח שלך, הבנייה הבאה שלך תכלול את הרכיב הזדוני, ואולי אפילו תבצע תוכנה זדונית בסקריפטי התקנה שעשויים להתבצע באופן אוטומטי. טשטוש מטען ההתקפה הוא סוג של אמנות.
זה ידוע בשם חוסר הצמדת גרסה נושא.
גורמים זדוניים תמיד מנסים להכניס גרסאות זדוניות של חבילות קוד פתוח פופולריות. הם עשויים לקבל גישה למפתחות של מאגרי חבילות בדליפה סודית; לעתים קרובות הם משתמשים בהנדסה חברתית או מסתירים תלות זדונית מקוננת בגישה לכאורה שימושית. pull requestאפילו כמה סופרים בעצמם מחליטים יום אחד שהעולם אינו הוגן ונושכים את לקוחותיהם עם כלי מחאה בחבילות משלהם!
עכשיו דמיינו שאתם עובדים בארגון שמשתמש ברכיבים פנימיים בנוסף לאלו בקוד פתוח.
אם גורם רע יודע את שם הרכיבים הפנימיים הללו, הוא/היא יכולים לפרסם רכיב עם אותו שם במאגר הציבורי. מנהלי חבילות רבים מקבלים תחילה את הרכיבים הציבוריים, ואם הגרסה נבחרה כראוי והגרסה בתלות המוצהרת שלך פתוחה, בום! בעיה זו נקראת בלבול תלות.
בואו נראה דוגמה. נניח שבפרויקט ה-NPM שלנו יש לנו תלות ברכיב פרטי:
- NPM: package.json
{
"שם": "הפרויקט-שלי",
...
"תלויות": {...
"המחלקה הפרטית-שלי": ">=1.0.0",...
}
...
}
התוקף עשוי ליצור גרסה ראשית גבוהה של my-private-dep (כגון 99.0.0) ולפרסם אותה במאגר npm הציבורי, עם חשבון מזויף משלו (התוקף אינו צריך לעשות דבר עם הארגון שלי). מנהל החבילות של NPM יתקין את התלות הזדונית, לרוב עם תוצאות הרסניות.
הפתרון
כדי להימנע מבעיות אלו בתהליך בניית התוכנה שלנו, עלינו לפעול לפי נורמות מחמירות לגבי אופן הצהרת גרסאות רכיבים, התלויות בטכנולוגיה בה נעשה שימוש. הדבר החשוב הוא שגרסה ספציפית של חבילה, לאחר שפורסמה במאגר, תהיה בלתי ניתנת לשינוי (כדי להימנע משבירת רכיבים תלויים, לא רק מסיבות אבטחה).
הרעיון הכללי הוא להתקבע (אורן) גרסאות, תוך בדיקה תמידית שהגרסאות הקבועות של הרכיבים (כולל כל התלויות הטרנזיטיביות) נקיות מתוכנות זדוניות, וזה אפשרי הודות ל- קבצי נעילה שמציעים מנהלי חבילות רבים. בואו נראה כיצד הצמדת גרסאות עובדת עבור מנהלי חבילות שונים. ישנה פשרה עדינה בין עדכוני גרסה תכופים לתיקון פגיעויות ידועות ו הצמדת גרסה כדי להימנע מבניית רשתות לא דטרמיניסטיות ומתקפות פוטנציאליות בשרשרת האספקה.
- NPM:
מנהלי החבילות npm או yarn משתמשים בקבצי נעילה שונים (npm-shrinkwrap.json / package-lock.json או yarn.lock, בהתאמה) המפרטים גרסאות קבועות עבור כל התלויות, ישירות ועקיפות. קבצי הנעילה צריכים להיות תחת בקרת גרסאות, אחרת מפתחים / צמתי בנייה אחרים עשויים לסיים עם גרסאות שונות. הימנעו מהתקנת npm אלא אם כן במהלך הפיתוח אתם צריכים לעדכן את התלויות (למשל, כדי להתקין תיקוני אבטחה). השתמשו באופן כללי ב-npm ci (התקנה נקייה) דטרמיניסטי יותר, כך שמנהל החבילות ישתמש בקובץ הנעילה או יסתיים עם שגיאה אם אין קובץ נעילה, או שהוא אינו תואם ל-package.json. אם הגרסאות המפורטות נבדקו לאיתור תוכנות זדוניות, קובץ הנעילה מבטיח ששום דבר רע לא יקרה בזמן הבנייה.עבור רכיבים פנימיים, מומלץ ליצור היקף NPM מנוהל על ידי הארגון (כמו @myorg), ולהשתמש בהיקף זה בתלות (כמו @myorg/my-private-dep), שיכולה להיות בעלת נראות פרטית בלבד. זה חוסם בלבול תלות התקפות, מכיוון שרק חבר בארגון עם גישת כתיבה יכול לפרסם חבילות תחת היקף כזה.
- NPM:
- Maven:
ל-Maven / Gradle אין קבצי נעילה (אבל ראו מאמר StackOverflow זה).טווחי גרסאות אינם בשימוש עם Maven/Gradle כמו במערכות אקולוגיות אחרות. פשוט הימנעו מ... טווחי גרסאות ומטא-גרסאות אחרונות או מהדורות. יש לבדוק גם גרסאות עקיפות. ה- גרסאות תוסף Maven הוא כלי נחמד לניהול גרסאות.
שימו לב של-Maven תמיד היה מושג של היקף ארגון (החלק groupId של התלות), ונראה בלעבול תלויות אינו מהווה בעיה כלל עבור מערכת אקולוגית זו.
- Maven:
- פְּעִים:
בפייתון ישנם כלים שונים לטיפול בקבצי נעילה:- פיפנב, אשר יוצר קובץ נעילה של Pipfile.lock.
- שירה, אשר יוצר poetry.lock.
- הקפאת פיפ, פקודה שמייצרת requirements.txt אשר משמש כקובץ נעילה. בדוק אם כל התלויות משתמשות בגרסאות קבועות בעזרת האופרטור ==. לאחר מכן, pip install -r requirements.txt משתמש בתלויות הקבועות.
- פְּעִים:
הזכירו שקבצי הנעילה שלמעלה צריכים להיות תחת בקרת גרסאות, ושפקודת הבנייה שנבחרה צריכה להשתמש בקובץ הנעילה.
מאגר החבילות הרגיל בו משתמשים עם pip (PyPI) אינו כולל טווחי מתן שמות, והוא פגיע להתקפות בלבול תלויות. הימנעות מבלבול תלויות במערכת האקולוגית של פייתון זה לא קל, וחלק מהמחברים ממליצים להשתמש במאגר פנימי שישמש כמתווך עבור תלויות ציבוריות הנלקחות מ-PyPI, אך לקחת תחילה את התלויות הפרטיות מהמאגר הפנימי (-index-url צריך להצביע למאגר הפנימי, לא ל-PyPI, ו-–extra-index- יש להסיר את url).
כמה התקפות אמיתיות
מתקפת Getcookiesהגורם dustin87 הוסיף תלות עקיפה לחבילת npm mailparser הפופולרית לחבילה זדונית עם דלת אחורית של RCE (gCOMMANDhDATAi):
JSON.stringify(req.headers).replace(/g([a-f0-9]{4})h((?:[a-f0-9]{2})+)i/gi, (o, p, v) => {})למרות שהוצא משימוש (אין בודקים!), mailparser עדיין קיבל כ-64,000 הורדות שבועיות. זה היה מקרה של התקפה כמעט-כמעט, מכיוון שה-RCE לא הופעל בפועל.cised.
NPM פורסם הודעה זו עם פרטים על מתקפת getcookies.
בלבול תלות:
אלכס בירסן גילה בשנת 2021 את בעיית בלבול התלות ופרסם פוסט שכותרתו "איך פרצתי לאפל, מיקרוסופט ועשרות חברות אחרות".
זכרו שעבור npm, יש לשמור את היקף הארגון כמו @myorg, ויש לשנות חבילות פנימיות כדי להשתמש בהיקף.
עם pip, הרישום הציבורי המשותף PyPI אינו כולל טווחי שמות. לכל חבילה פרטית יכולה להיות חבילה ציבורית ריקה עם אותו שם כמו החבילה הפנימית, ואולי תיצור שגיאה בעת השימוש, כך שניתן יהיה לזהות אותה אם היא נלקחת בטעות.
Node-ipc:
בעל החבילה, כאשר החלה מלחמת רוסיה-אוקראינה, הזריק קוד זדוני להסרת קבצים אקראיים, כאשר הותקן במארחים רוסיים ובלארוסיים. הקובץ ssl-geospec.js ביצע את ההבחנה הגיאוגרפית הבאה:
מעניין לציין, חבילות אחרות השתמשו בגרסאות פתוחות עבור התלות בין node ל-ipc, כמו מסגרת Vue.js הפופולרית, והתחזקים שלה קיבלו ערעור דחוף כדי להצמיד את התלות של node-ipc לגרסה בטוחה.
זֶה הפוסט מכיל פרטים נוספים על החבלה הזו, שהולכת צעד קדימה מאחרות כלי מחאה נושאים.
הערות סיכום
גרסאות פתוחות צריכות לעולם לא לשמש בפרויקטים מאוחדים של תוכנה. הם הופכים את הבנייה לבלתי ניתנת לשחזור, ותוקפים עלולים לנצל אותה ולהצליח להחדיר תוכנות זדוניות באמצעות התקפות על עצי התלות כמו בלבול התלות שהוזכר לעיל.
תצורות שגויות כמו גרסאות פתוחות, חוסר הצמדת גרסה, או רכיבים פנימיים ללא טווח יש להימנע מהם. הדבר הראשון הוא לזהות בעיות כאלה, אולי אפילו לחסום את הבנייה כאשר הן נמצאות, ולגבש פרוטוקול פעולה סטנדרטי.
זיהוי אוטומטי של פגמים ותצורות שגויות בתלות, דיווח על תלויות חשודות שעלולות להיות פגיעות להתקפות ספציפיות בשרשרת האספקה כמו בלבול תלות, הכל עם כלי תיקון מעשיים, היא אחת המטרות העיקריות של ה- פלטפורמת Xygeni.
| לקריאה נוספת |
| Ohm M., Plate H., Sykosch A., Meier M.: "אוסף סכינים של דוקרני גב: סקירה של מתקפות שרשרת אספקה של תוכנה בקוד פתוח". DIMVA 2020. הערות הרצאה במדעי המחשב, כרך 12223. ספרינגר – 2020 (מקור איור עץ מתקפת התלות). |
| @adam-npm: "מודול זדוני שדווח: getcookies"בלוג npm (ארכיון) – 2 במאי, 2018." |
| אלכס בירסן: "איך פרצתי לאפל, מיקרוסופט ועשרות חברות אחרות". מדיום – 9 בפברואר, 2021. |
| אקס שארמה: "חבלה גדולה: חבילת npm המפורסמת מוחקת קבצים במחאה על מלחמת אוקראינה"מחשב מצפצף – 17 במרץ, 2022" |







