הסופר בחר את Girls Who Code כדי לקבל תרומה כחלק מהתוכנית כתוב בשביל תרומות.
הקדמה
כאשר אתה מבקר באתר, מקורות שונים משמשים לטעינה ולהצגתו. כדוגמת, כאשר אתה הולך אל https://www.digitalocean.com
, הדפדפן שלך מוריד את ה-HTML וה-CSS ישירות מ-digitalocean.com
. אולם, התמונות ומשאבים אחרים מורדים מ-assets.digitalocean.com
, וסקריפטים לניתוח מורדים מדומיינים המתאימים להם.
קצת אתרי אינטרנט משתמשים במגוון של שירותים שונים, סגנונות וסקריפטים לטעינה ולהצגת התוכן שלהם, והדפדפן שלך יפעל את כל אלו. דפדפן אינו יודע אם הקוד זדוני, לכן זה באחריותו של המפתח להגן על המשתמשים. מכיוון שיכולה להיות הרבה משאבים באתר, יש בדפדפן יכולת שמאפשרת רק משאבים מאושרים, מה שמהווה דרך טובה להבטיח שהמשתמשים לא ייחשפו. זהו מה שמדיניות אבטחת התוכן (CSPs) עושה.
באמצעות כותרת CSP, מפתח יכול להרשות באופן פורמלי למשאבים מסוימים לרוץ תוך מניעת כל האחרים. מאחר ורוב האתרים יכולים לכלול עד מאות משאבים, וכל אחד חייב להיות מאושר עבור הקטגוריה הספציפית של המשאב, החידוש של מדיניות CSP יכול להיות משימה מתישה. אך אתר עם CSP יהיה יותר מאובטח מאשר כי הוא מבטיח רק משאבים מאושרים יורים.
במדריך זה, תטמיע CSP באפליקציה בסיסית של Django. תדמיע את ה-CSP בכדי לאפשר דומיינים מסוימים ומשאבים מטמוניים לרוץ. לפי בחירתך, תוכל גם להשתמש ב-Sentry כדי לרשום עבירות.
דרישות קדם
כדי להשלים את המדריך הזה, תצטרך:
- A working Django project (version 3 or greater is preferred), either on your local machine or a DigitalOcean Droplet. If you don’t have one, you can create one with the tutorial, How to Install Django and Set Up a Development Environment on Ubuntu 20.04.
- A web browser like Firefox or Chrome and an understanding of browser network tools. For more on using browser network tools, check out the product documentation for the Network Monitor in Firefox or the DevTools Network Tab in Chrome. For more general guidance on browser developer tools, see the guide: What are Browser Developer Tools?
- ידע ב-Python 3 וב-Django, אשר תוכל לקבל מסדרת המדריכים, איך לכתוב ב-Python ו-פיתוח Django.
- חשבון ב-Sentry למעקב אחר עבירות ה-CSP (אופציונלי).
שלב 1 — יצירת תצוגה דמו
בשלב זה, תשנה את אופן טיפול התצוגות באפליקציה שלך כך שתוכל להוסיף תמיכה ב-CSP.
כדי להשלים את זה, התקנת את Django והגדרת פרויקט דוגמה. התצוגה הברירת מחדל של Django היא יותר מדי פשוטה כדי להדגיש את כל היכולות של תיקון ה-CSP, לכן תיצור דף HTML פשוט למדריך זה.
נווט אל תיקיית הפרויקט שיצרת בדרישות הקדם:
בעודך בתיקיית django-apps
, צור את הסביבה הווירטואלית שלך. נקרא לה env
, אך אתה יכול להשתמש בשם שכדאי עבורך ועבור הפרויקט שלך.
עכשיו, הפעל את הסביבה הווירטואלית באמצעות הפקודה הבאה:
בתוך הסביבה הווירטואלית, צור קובץ views.py
בתיקיית הפרויקט שלך באמצעות nano
, או העורך הטקסט שאתה מעדיף:
עכשיו, תוסיף תצוגה בסיסית שתציג תבנית index.html
שתיצור אחר כך. הוסף את הבא ל־views.py
:
שמור וסגור את הקובץ כאשר אתה מוכן.
צור תבנית index.html
בתיקיית templates
חדשה:
הוסף את הבא ל־index.html
:
התצוגה שיצרת תציג את עמוד ה־HTML הפשוט הזה. הוא יציג את הטקסט Hello, Sammy! יחד עם תמונה של סמי הכריש.
שמור וסגור את הקובץ כאשר אתה מוכן.
כדי לגשת אל התצוגה הזו, תצטרך לעדכן את urls.py
:
ייבא את קובץ views.py
והוסף מסלול חדש על ידי הוספת השורות המודגשות:
התצוגה החדשה שיצרת כעת תהיה נגישה כאשר אתה מבקר ב־/
(כאשר היישום רץ).
שמור וסגור את הקובץ.
לבסוף, תצטרך לעדכן את INSTALLED_APPS
כך שיכלול את testsite
ב־settings.py
:
הוסף את testsite
לרשימת היישומים ב-settings.py
כך ש-Django יכול להניח משהו על מבנה הפרויקט שלך. במקרה זה, זה יניח שתיקיית templates
מכילה תבניות Django שניתן להשתמש בהן לעיצוב תצוגות.
מתוך ספריית השורש של הפרויקט (testsite
), התחל את שרת הפיתוח של Django עם הפקודה הבאה, והחלף את כתובת-ה-IP-של-השרת-שלך
בכתובת ה-IP של השרת שלך.
פתח דפדפן ובקר ב־כתובת-ה-IP-שלך:8000
. הדף צריך להיראות דומה לכזה:
בנקודה זו, הדף מציג תמונת פרופיל של סמי הכריש. מתחת לתמונה יש הטקסט Hello, Sammy! בצבע כחול.
כדי לעצור את שרת הפיתוח של Django, לחץ על CONTROL-C
.
בשלב זה, יצרת תצוגה בסיסית שמשמשת כעמוד הבית של פרויקט Django שלך. בשלב הבא, תוסיף תמיכה ב-CSP ליישום שלך.
שלב 2 — התקנת תוכנה ביניים של CSP
בשלב זה, תתקין ותממש תוכנה ביניים של CSP כך שתוכל להוסיף כותרות CSP ולעבוד עם תכונות CSP בתצוגות שלך. תוכנה ביניים מוסיפה תכונות נוספות לכל בקשה או תגובה ש-Django מטפלת בה. במקרה זה, התוכנה הביניים של תוכנה ביניים של Django-CSP מוסיפה תמיכה ב-CSP לתגובות של Django.
ראשית, תתקין את מרכז השירותים הביטחוניים של Mozilla בפרויקט Django שלך באמצעות pip
, מנהל החבילות של Python. השתמש בפקודה הבאה כדי להתקין את החבילה הנדרשת מ־PyPi, אינדקס החבילות של Python. כדי להריץ את הפקודה, תוכל לעצור את שרת הפיתוח של Django באמצעות CONTROL-C
או לפתוח לשונית חדשה בטרמינל שלך:
הבא את המידע שנדרש לפרויקט Django שלך. פתח את settings.py
:
עם התקנת django-csp
, כעת תוכל להוסיף את מרכז השירותים הביטחוניים ב־settings.py
של הפרויקט שלך. זה יוסיף כותרות CSP לתגובות שלך.
הוסף את השורה הבאה למערך התצורה של MIDDLEWARE
:
שמור וסגור את הקובץ כאשר תסיים. הפרויקט שלך ב־Django כעת תומך ב־CSP. בשלב הבא, תתחיל להוסיף כותרות CSP.
שלב 3 — מימוש כותרת CSP
כעת שהפרויקט שלך תומך ב־CSP, הוא מוכן להתחזק באופן אבטחתי. כדי להשיג זאת, תקבע את הפרויקט כך שיתווסף כותרות CSP לתגובות שלך. כותרת CSP היא מה שאומרת לדפדפן כיצד להתנהג כאשר הוא נתקל בסוג תוכן מסוים. לכן, אם הכותרת אומרת לאפשר רק תמונות מדומיין מסוים, אז הדפדפן יאפשר רק תמונות מהדומיין הזה.
באמצעות nano או העורך הטקסט האהוב עליך, פתח את settings.py
:
הגדר את המשתנים הבאים בכל מקום בקובץ:
החוקים הללו הם הבסיס ל־CSP שלך. שורות אלו מציינות אילו מקורות מורשים לתמונות, גיליונות סגנון, ותסריטים, בהתאמה. כרגע, כל אלו מכילים את המחרוזת 'self'
, שפירושה שרק משאבים מדומיינך האישי מורשים.
שמור וסגור את הקובץ כשתסיים.
הרץ את פרויקט ה־Django שלך עם הפקודה הבאה:
כאשר אתה מבקר ב־כתובת-ה-שרת-שלך:8000
, תראה שהאתר שבור:
כפי שצפוי, התמונה לא מופיעה והטקסט מופיע בעיצוב ברירת מחדל (מודגש שחור). זה אומר שכותרת ה־CSP מיושמת, והעמוד שלנו כעת יותר מאובטח. בגלל שהתצוגה שיצרת קוראת לגיליונות סגנון ולתמונות מדומיינים שלא שייכים לך, הדפדפן מונע אותם.
פרויקטך כעת כולל CSP פעיל שמורה לדפדפן לחסום משאבים שאינם מהדומיין שלך. בשלב הבא, תשנה את CSP כדי לאפשר משאבים מסוימים, שיפתרו את בעיה התמונה החסרה והעיצוב בדף הבית.
שלב 4 — שינוי ה־CSP כדי לאפשר משאבים חיצוניים
עכשיו שיש לך CSP בסיסי, תשנה אותו על פי מה שאתה משתמש בו באתר שלך. כדוגמה, אתר שמשתמש בגופני Adobe ובסרטוני YouTube מוטבעים יצטרך לאפשר את המשאבים האלה. אם עם האתר שלך מציג רק תמונות מתוך דומיין האתר שלך, תוכל להשאיר את ההגדרות של התמונות בברירת המחדל המוגבלת שלהם.
השלב הראשון הוא למצוא כל משאב שתצטרך לאשר. תוכל להשתמש בכלי הפיתוח של הדפדפן שלך כדי לעשות זאת. פתח את מוניטור הרשת ב-בדיקת אלמנט, רענן את הדף ובדוק את המשאבים שחסומים:
יומן הרשת מציג שני משאבים שחסומים על ידי ה- CSP: גיליון סגנון מתוך fonts.googleapis.com
ותמונה מתוך html.sammy-codes.com
. כדי לאפשר את המשאבים הללו בכותרת ה- CSP, תצטרך לשנות את המשתנים בתוך settings.py
.
כדי לאפשר משאבים מדומיינים חיצוניים, הוסף את הדומיין לחלק ה- CSP שמתאים לסוג הקובץ. אז, כדי לאפשר תמונה מתוך html.sammy-codes.com
, תוסיף html.sammy-codes.com
לתוך CSP_STYLE_SRC
.
פתח את settings.py
והוסף את המשתנה הבא לתוך המשתנה CSP_STYLE_SRC
:
כעת, במקום לאפשר רק תמונות מהדומיין שלך, האתר מאפשר גם תמונות מתוך html.sammy-codes.com
.
התצוגה האינדקסית משתמשת בגופני Google. Google מספקת לאתר שלך את הגופנים (מתוך https://fonts.gstatic.com
) וגם עטיפת עיצוב להחיל אותם (מתוך https://fonts.googleapis.com
). כדי לאפשר טעינת הגופנים, הוסף את הקוד הבא למדיניות האבטחה שלך:
דומה לאפשר תמונות מתוך html.sammy-codes.com
, עליך גם לאפשר גליונות עיצוב מתוך fonts.googleapis.com
וגופנים מתוך fonts.gstatic.com
. להקשר, גליון העיצוב הנטען מתוך fonts.googleapis.com
משמש להחלת הגופנים. הגופנים עצמם נטענים מתוך fonts.gstatic.com
.
שמור וסגור את הקובץ.
אזהרה: דומה ל־self
, קיימים מילות מפתח נוספות כגון unsafe-inline
, unsafe-eval
, או unsafe-hashes
שניתן להשתמש בהן במדיניות ה־CSP. מומלץ מאוד להימנע משימוש בכללי אלו במדיניות ה־CSP שלך. בעוד שהם עשויים להקל על היישום, הם יכולים לשמש להימנע מה־CSP ולהפוך אותו לבלתי פעיל.
למידע נוסף, ראה את תיעוד המוצר של Mozilla עבור "Unsafe inline script".
כעת, יאושר ל־Google Fonts לטעון סגנונות וגופנים באתר שלך ו־html.sammy-codes.com
יורשה לטעון תמונות. עם זאת, כאשר אתה מבקר בעמוד בשרת שלך, ייתכן ותגלה כי כעת נטענות רק תמונות. זה בגלל שהסגנונות הפנימיים ב־HTML שמשמשים להחלת הגופנים אינם מאושרים. תתקן את זה בשלב הבא.
שלב 5 — עבודה עם קודי סקריפט וסגנונות מוטבעים
בנקודה זו, שינית את CSP כדי לאפשר משאבים חיצוניים. אך משאבים מוטבעים, כמו סגנונות וסקריפטים בתצוגה שלך, עדיין לא מורשים. בשלב זה, תקבל את הפעלתם כך שתוכל ליישם עיצוב פונט.
קיימות שתי דרכים לאפשר סקריפטים וסגנונות מוטבעים: nonces ופוקודות. אם תגלה שאתה משנה תכניות סקריפט וסגנונות מוטבעים בתדירות, השתמש ב nonces כדי למנוע שינויים תדירים ב CSP שלך. אם אתה מעדכן תכניות סקריפט וסגנונות מוטבעים לעתים רחוקות, שימוש בפוקודות הוא גישה סבירה.
שימוש ב nonce
כדי לאפשר סקריפטים מוטבעים
למשל, תשתמש בגישת ה nonce. nonce הוא טוקן שנוצר באופן אקראי שהוא ייחודי לכל בקשה. אם שני אנשים מבקרים באתר שלך, כל אחד יקבל nonce ייחודי שמוטבע בסקריפטים ובסגנונות מוטרים שאתה מאשר. חשוב לחשוב על nonce כעל סיסמה חד פעמית שמאשרת חלקים מסוימים של אתר לרוץ במהלך ישיבה אחת.
כדי להוסיף תמיכה ב nonce לפרוייקט שלך, תעדכן את CSP שלך ב settings.py
. פתח את הקובץ לעריכה:
הוסף script-src
ב־CSP_INCLUDE_NONCE_IN
בקובץ settings.py
.
הגדר את CSP_INCLUDE_NONCE_IN
בכל מקום בקובץ והוסף אליו את 'script-src'
:
CSP_INCLUDE_NONCE_IN
מציין אילו סקריפטים משולבים ניתן להוסיף את תכונת ה־nonce
אליהם. CSP_INCLUDE_NONCE_IN
מטופל כמערך מאחר ומקורות נתונים מרובים תומכים ב־nonce
(לדוגמה, style-src
).
שמור וסגור את הקובץ.
כעת ניתן ליצור nonce
עבור סקריפטים משולבים כאשר אתה מוסיף את תכונת ה־nonce
אליהם בתבנית התצוגה שלך. כדי לנסות זאת, נשתמש בקטע קוד פשוט.
פתח את index.html
לעריכה:
הוסף את הקטע הבא בתוך <head>
של HTML:
קטע הקוד הזה מדפיס Hello from the console!"
לקונסול של הדפדפן. אולם, מאחר ולפרויקט שלך יש CSP שמאפשר רק סקריפטים משולבים אם יש להם nonce
, סקריפט זה לא ירוץ ויצירת שגיאה במקום.
אפשר לראות את השגיאה הזו בקונסול של הדפדפן שלך כאשר אתה מרענן את הדף:
התמונה נטענת מאחר ואישרת מקורות חיצוניים בשלב הקודם. כצפוי, העיצוב כרגע הוא ברירת המחדל מאחר ועדיין לא אפשרת סגנון משולב. כמו כן, הודעת הקונסול לא הודפסה והחזירה שגיאה. תצטרך לתת לה nonce
כדי לאשר אותה.
אתה יכול לעשות זאת על ידי הוספת nonce="{{request.csp_nonce}}"
לסקריפט כקניין. פתח את index.html
לעריכה והוסף את החלק המודגש כפי שמוצג כאן:
שמור וסגור את הקובץ כאשר תסיים.
אם תרענן את הדף, הסקריפט יפעל כעת:
כאשר אתה מבצע בדיקה ב- גלוריה, תשים לב שאין ערך עבור המאפיין:
הערך לא מופיע מסיבות אבטחה. הדפדפן כבר עיבד את הערך. הוא מוסתר כך שסקריפטים עם גישה ל-DOM לא יכולים לגשת אליו ולהחיל אותו על סקריפט אחר. אם תצפה ב- מקור הדף במקום, זה מה שהדפדפן קיבל:
שים לב שבכל פעם שתרענן את הדף, הערך של nonce
משתנה. זה מפני שקישוריות המודל CSP בפרויקט שלנו יוצרת nonce
חדש לכל בקשה.
ערכי ה- nonce
הללו מוסיפים לכותרת ה- CSP כאשר הדפדפן מקבל את התגובה:
כל בקשה שהדפדפן עושה לאתר שלך תכיל ערך ייחודי של nonce
עבור אותו סקריפט. מאחר שה- nonce
ניתן בכותרת ה- CSP, זה אומר שהשרת Django אישר סקריפט מסוים זה להרוץ.
עדכנת את הפרויקט שלך כך שהוא יעבוד עם nonce, שניתן להחיל על מקורות מרובים. לדוגמה, תוכל להחיל אותו על סגנונות גם, על ידי עדכון של CSP_INCLUDE_NONCE_IN
כך שיאפשר style-src
. אבל יש גישה פשוטה יותר לאישור משאבים באינליין, וזו הגישה שתעשה אחר כך.
שימוש בפונקציות האש לאפשר סגנונות בתוך המסמך
גישה נוספת לאפשר סקריפטים וסגנונות בתוך המסמך היא באמצעות פונקציות האש. האש הוא זיהוי ייחודי למשאב מוטבע מסוים.
כדוגמת, זהו הסגנון המוטבע בתבנית שלנו:
כרגע, למרבה המזל, הסגנונות לא פועלים. כאשר אתה צופה באתר בדפדפן, התמונות נטענות בהצלחה, אך הגופנים והסגנונות לא מתוישים:
בקונסולת הדפדפן, תמצא שגיאה כי סגנון מוטבע מפר את מדיניות האבטחה. (יתכן וישנן שגיאות אחרות, אך חפש את השגיאה הנוגעת לסגנון מוטבע.)
השגיאה נגרמת מכך שהסגנון לא מאושר על ידי מדיניות האבטחה שלנו. אך, שים לב שהשגיאה מספקת את האש הנחוץ לאישור הקטע הסגנוני. האש הזו היא ייחודית לקטע הסגנוני המסוים הזה. לעולם לא יהיו לקטעים אחרים את אותה האש. כאשר האש הזו מוכנסת למדיניות האבטחה, בכל פעם שהסגנון הספציפי הזה נטען, הוא ייאושר. אך, אם תשנה את הסגנונות אי פעם, תצטרך לקבל את האש החדש ולהחליף אותו באש הישן במדיניות האבטחה.
עכשיו תיישם את האש על ידי הוספתו ל־CSP_STYLE_SRC
ב־settings.py
, כך:
להוסיף את האש sha256-...
לרשימת CSP_STYLE_SRC
תאפשר לדפדפן לטעון את גליון הסגנון בלי שגיאות.
שמור וסגור את הקובץ.
עכשיו, טען מחדש את האתר בדפדפן, והגופנים והסגנונות צריכים להיטענו בהצלחה:
סגנונות ותסריטים מוטבעים כעת פועלים בצורה תקינה. בשלב זה, השתמשת בשני גישות שונות, nonces ו־hashes, כדי לאפשר סגנונות ותסריטים מוטבעים.
אך, ישנה בעיה חשובה לטפל בה. מדיניות האבטחה של התכנית Content Security Policy (CSP) דורשת תחזוקה מפרך, במיוחד עבור אתרי אינטרנט גדולים. עשוי להיות נחוץ דרך לעקוב מתי ה־CSP חוסם משאב, כדי שתוכל לקבוע האם זהו משאב זדוני או פשוט חלק מקור האתר שבו. בשלב הבא, תשתמש ב־Sentry כדי לרשום ולעקוב אחר כל ההפרות שנגרמות על ידי תקני ה־CSP שלך.
שלב 6 — דיווח על הפרות עם Sentry (אופציונלי)
בהתחשב בכך שמדיניות ה־CSP נוטים להיות מחמירות, כדאי לדעת מתי היא חוסמת תוכן — במיוחד מאחר שחסימת תוכן ככל הנראה אומרת שחלק מהפונקציונליות באתר שלך לא תעבוד. כלים כמו Sentry יכולים להודיע לך כאשר ה־CSP חוסמת בקשות עבור משתמשים. בשלב זה, תגדיר את Sentry כך שתרשום ותדווח על הפרות ב־CSP.
כדי להשתמש בכך, נדרש להירשם לחשבון עם Sentry. כעת תיצור פרויקט.
בפינה השמאלית העליונה של לוח המחוונים של Sentry, לחץ על הכרטיסייה פרויקטים:
בפינה הימנית העליונה, לחץ על כפתור צור פרויקט:
תראו מספר לוגואים עם כותרת המציינת בחרו פלטפורמה. בחרו Django:
אז, בתחתית, תתווסף את שם הפרוייקט שלכם (לדוגמה, נשתמש ב-sammys-tutorial
), ולחצו על הכפתור צור פרויקט:
סנטרי תציע לך קטע קוד להוספה לקובץ ה-settings.py
. שמרו את קטע הקוד הזה כדי להוסיף אותו בשלב מאוחר יותר.
בטרמינל שלכם, התקינו את ה-SDK של Sentry:
פתחו את settings.py
בצורה הבאה:
הוסיפו את התוכן הבא לסוף הקובץ, וודאו שאתם מחליפים את SENTRY_DSN
בערך מלוח המחוון:
קטע הקוד הזה מסופק על ידי Sentry כך שיהיה אפשר לרשום כל שגיאות שמתרחשות ביישום שלך. זהו הגדרת ברירת המחדל של Sentry ומאתחל את Sentry עבור רישום בעיות בשרת שלנו. מבחינה טכנית, אין צורך באיתחול של Sentry על השרת שלך עבור הפרצות של מדיניות האבטחה, אך במקרה נדיר ייתכן שיהיה בעיה בהצגת nonces או hashes, שגיאות אלו יורשמו ל-Sentry.
שמרו וסגרו את הקובץ.
אז חזור ללוח המחוונים של הפרויקט שלך ולחץ על סמל הגלגלת כדי להיכנס להגדרות:
עבור לכרטיסיית ראשי האבטחה:
העתק את ה- דיווח-uri
:
הוסף אותו ל-CSP שלך בדרך הבאה:
ודא שאתה מחליף את דיווח-uri שלך
בערך שהעתקת מהלוח.
שמור וסגור את הקובץ שלך. עכשיו, כאשר האכיפה של ה-CSP גורמת להפרה, Sentry תירשם אותה ל-URI הזה. אתה יכול לנסות זאת על ידי הסרת דומיין או קיבוץ מ-CSP שלך, או על ידי הסרת ה-nonce
מהתסריט שהוספת בתחילה. טען את העמוד בדפדפן ותראה את השגיאה בדף בעיות של Sentry:
אם תגלה שאתה מועמד מספר הלוגים, תוכל גם להגדיר את
CSP_REPORT_PERCENTAGE
ב- settings.py
כדי לשלוח רק אחוז מהלוגים ל-Sentry.
עכשיו כל פעם שיש הפרת CSP, תקבל התראה ותוכל להציג את השגיאה ב-Sentry.
מסקנה
במאמר זה, כיסית את היישום שלך ב־Django במדיניות אבטחת תוכן. עדכנת את המדיניות שלך כך שתאפשר משאבים חיצוניים, ומשתמשת ב־nonces וב־hashes כדי לאפשר סקריפטים וסגנונות מוטבעים. כמו כן, הגדרת אותה כך שתשלח הפרות ל־Sentry. כשלב הבא, בדוק את מסמך התיעוד של Django CSP כדי ללמוד עוד על כיצד לאכוף את ה־CSP שלך.