ב-5.6 העברתי הרצאה על משטח התקפה שנקרא ׳Supply Chain Attack׳ בכנס גיקטיים קוד. אני מאוד אוהב את גיקטיים – גם לקרוא וגם את הכנסים והאירועים שלהם. בהרצאה דיברתי על מה זה בכלל וכרגיל באבטחת מידע – יש הרבה מונחים מסובכים אבל העקרון פשוט. בהרצאה הדגמתי על אתרים מבוססים Node.js אבל זה רלוונטי לכל טכנולוגיה ולכל אפליקציה. המאמר הזה מצריך הכרות עם CSP שכתבתי עליו במאמר קודם.
בגדול, Supply Chain היא שרשרת האספקה של המוצר שלנו. מה זה אומר? זה אומר תוכנות, תשתיות והצינור שהמוצר שלנו עובר עד לאספקה. דוגמאות? ה- Node modules היא דוגמה קלאסית. או תוספים לוורדפרס. או וורדפרס עצמה לצורך העניין. או קלאסים של PHP. או כל דבר אחר שאנחנו לא כותבים. אם אני יוצר אתר וורדפרס למשל וכותב לו קוד – הקוד שאני כותב יכול להיות הכי מאובטח בעולם אבל אם בבניית האתר אני משתמש בתוסף עם קוד ׳מורעל׳ אני בבעיה. אם מישהו הצליח להשתיל חולשה בוורדפרס, אני בבעיה. אם אני משתמש ב Docker Image בעייתי לדיפלוימנט אני בבעיה. אם מישהו מבצע התקפה על המוצר שלי דרך שימוש בחולשות כאלו – הוא התקיף אותי ב-Supply Chain Attack.
בהרצאה סקרתי כמה התקפות מוצלחות כאלו שכתבתי עליהן גם באתר וגם ב׳הארץ׳. כמו למשל המתקפה המוצלחת על eslint. או ההתקפה המהממת על Copay – שבמסגרתה תוקף הצליח להשיג גישה למודול איזוטרי של NPM שהיה כ-dependency של מוצר בשם Copay (כתבה ב׳הארץ׳).
התקפות אחרות שדיברתי עליהם בהתקפה הן פחות התקפות על התלויות ויותר התקפות על אינטגרציות של שירותי צד שלישי. מה זה אומר? כל קריאה לסקריפט/CSS חיצוני זו קריאה לשירות צד שלישי. זה יכול להיות לפייסבוק, זה יכול להיות לגוגל אנליטיקס, תוסף נגישות, הטמעה של וידאו – You name it. ראינו התקפה כזו על Ynet ומיליון דפים ישראלים כשתוקף הצליח להשיג גישה לסקריפט הנגישות של חברת Nagich ומשם בעצם לכל אתר שהטמיע אותו. התוקף היה יכול להריץ קוד ג׳אווהסקריפט בכל שרת שהוא שהטמיע את השירות הזה.
בניית אתר ווב מודרני אומרת שהרבה פעמים אנו צריכים להטמיע שירותי צד שלישי באתר שלנו – איך אנחנו עושים את זה באופן מאובטח? איך אנחנו מונעים מתוקף צד שלישי לשנות את הקוד מצד אחד ומצד שני להמנע מלהציב את כל הסקריפטים של שירותי צד ג׳ אצלנו על השרת?
התשובה היא SRI. יכולת לאמת את הסקריפטים וה-CSSים באמצעות CSP. כל משאב חיצוני מהסוגים האלו שנטען באתר – אפשר לאמת אותו ולוודא שהסקריפט הזה הוא באמת כפי שהוא.
איך עושים את זה? ראשית מכירים את פונקצית הגיבוב (hash). הפונקציה הזו לוקחת קובץ, כל קובץ שהוא, ומחזירה ערך ייחודי (או כמעט ייחודי). אני יכול לבצע את החישוב הזה עם מספר אלגוריתמים שונים של גיבוב (כמו SHA למשל) ואז לכל קובץ שעשיתי לו את החישוב הזה יש hash ייחודי. שיניתי את הקובץ ולו בתו אחד? הוספתי אפילו רווח? ה-hash משתנה. אני מחשב את ה-hash הזה עבור כל ג׳אווהסקריפט ממקור צד שלישי שאני טוען לאתר שלי (או לפחות אלו ממקורות חשודים או מפוקפקים מעט) ובכל טעינה אני יכול להורות לדפדפן לוודא שה-hash של הקובץ תואם ל-hash שחישבתי – כלומר הקובץ הוא אותו קובץ בלי ׳הפתעות׳. במידה והקובץ משתנה? אני יכול להורות לדפדפן לשגר בקשה מיוחדת כדי להתריע בפני שמשהו בסקריפט החיצוני השתנה ואז אני יכול לבחון את השינוי ולהחליט אם לחשב את ה-hash מחדש (ולצעוק על הספק של הצד השלישי על זה שהוא שינה את הסקריפט בלי להודיע) או שבאמת מדובר פה בתקיפה. כך או כך – הסקריפט לא ייטען אם היה שינוי.
איך עושים את זה:
- ב-CSP מציינים בפירוש את אחת האפשרוית הבאות (בהתאם למשאב שאנו רוצים לוודא):
Content-Security-Policy: require-sri-for script;
Content-Security-Policy: require-sri-for style;
Content-Security-Policy: require-sri-for script style;
2. על כל קובץ מחשבים את ה-hash באמצעות:
cat path/to/file.js | openssl dgst -sha384 -binary | openssl base64 -A
3. את ה-hash שהומר ל-base64 מציבים בתגית ה-script תחת integrity. למשל:
<script src='/javascript/good.js'
integrity="sha384-Ss2b9qke0JugcHFBO4J0cg+w4u1AkpdluWsNaEknSp6XLmcMZZ84Xx31EzSFixH5"
></script>
מהנקודה הזו, אם חל שינוי בקובץ וה-hash שלו השתנה, הוא לא יטען יותר ונקבל שגיאה.
הפיצ׳ר הזה אולטרא שימושי בהרבה מקומות. במיוחד אם יש לכם שירותי צד שלישי שאתם מחויבים לטעון מהשרת של הצד השלישי אבל אתם רוצים לוודא שהוא לא נפרץ. לא הייתי משתמש בהם בכל מקום – אבל כן שווה להכניס את ה-SRI בכל מקום שאפשר.
3 תגובות
אם הקובץ שאני צריך לטעון לא אמור להשתנות, אני יכול פשוט לקחת אותו אליי לשרת ולטעון אותו ממני.
כך אף אחד לא יכול לשנות אותו.
וגם האתר שלי לא תלוי בשירותים אחרים.
זה אומר שלא מומלץ להשתמש ב
https://cdn.jsdelivr.net/npm/vue
אלה רק בגירסה ספציפית?
Great note!
Thank you for sharing.
If you are very lazy (like myself), you can use:
SRI Hash Generator
https://www.srihash.org/
(but it always good to make sure the hash are correct)
For that you could use:
curl -s https://something.com/link_to_css_or_JS_file.js | openssl dgst -sha384 -binary | openssl base64 -A