מדריך מקיף לחיזוק אבטחת צד הלקוח באמצעות Content Security Policy (CSP) ושיתוף משאבים חוצי מקורות (CORS), להגנה מפני איומים מודרניים.
הידוק אבטחת צד הלקוח: Content Security Policy ו-CORS
בעולם הדיגיטלי המקושר של ימינו, אבטחת צד הלקוח היא בעלת חשיבות עליונה. יישומי אינטרנט הופכים למטרות תכופות יותר של התקפות מתוחכמות, מה שהופך אמצעי אבטחה חזקים לחיוניים. שני מרכיבים קריטיים בארכיטקטורת אבטחת צד לקוח הם Content Security Policy (CSP) ו-Cross-Origin Resource Sharing (CORS). מדריך מקיף זה מספק מבט מעמיק על טכנולוגיות אלו, ומציע דוגמאות מעשיות ותובנות יישומיות שיעזרו לכם לחזק את יישומי האינטרנט שלכם מפני איומים מודרניים.
מהי מדיניות אבטחת תוכן (CSP)?
מדיניות אבטחת תוכן (CSP) היא שכבת אבטחה נוספת המסייעת לזהות ולהפחית סוגים מסוימים של התקפות, כולל Cross-Site Scripting (XSS) והתקפות הזרקת נתונים. CSP מיושמת על ידי שרת האינטרנט ששולח כותרת תגובת HTTP של Content-Security-Policy לדפדפן. כותרת זו מגדירה רשימה לבנה של מקורות מהם הדפדפן מורשה לטעון משאבים. על ידי הגבלת מקורות התוכן שהדפדפן יכול לטעון, CSP מקשה באופן משמעותי על תוקפים להזריק קוד זדוני לאתר שלכם.
כיצד פועל CSP
CSP פועל על ידי הנחיית הדפדפן לטעון משאבים (לדוגמה, סקריפטים, גיליונות סגנון, תמונות, גופנים) רק ממקורות מאושרים. מקורות אלה מצוינים בכותרת ה-CSP באמצעות דירקטיבות. אם דפדפן מנסה לטעון משאב ממקור שאינו מותר במפורש, הוא יחסום את הבקשה וידווח על הפרה.
דירקטיבות CSP: סקירה מקיפה
דירקטיבות CSP שולטות בסוגי המשאבים שניתן לטעון ממקורות ספציפיים. הנה פירוט של כמה מהדירקטיבות החשובות ביותר:
- default-src: מציין את מקור ברירת המחדל לכל סוגי התוכן. זוהי דירקטיבת חלופה החלה כאשר דירקטיבות אחרות, ספציפיות יותר, אינן קיימות.
- script-src: מציין את המקורות מהם ניתן לטעון סקריפטים. זה חיוני למניעת התקפות XSS.
- style-src: מציין את המקורות מהם ניתן לטעון גיליונות סגנון.
- img-src: מציין את המקורות מהם ניתן לטעון תמונות.
- font-src: מציין את המקורות מהם ניתן לטעון גופנים.
- media-src: מציין את המקורות מהם ניתן לטעון אודיו ווידאו.
- object-src: מציין את המקורות מהם ניתן לטעון תוספים (לדוגמה, Flash). זה לרוב מוגדר ל-'none' כדי להשבית תוספים לחלוטין בשל סיכוני האבטחה המובנים שלהם.
- frame-src: מציין את המקורות מהם ניתן לטעון פריימים (לדוגמה, <iframe>).
- connect-src: מציין את כתובות ה-URL אליהן סוכן המשתמש יכול להתחבר באמצעות ממשקי סקריפט כגון XMLHttpRequest, WebSocket ו-EventSource.
- base-uri: מציין את כתובות ה-URL שניתן להשתמש בהן באלמנט ה-<base> של מסמך.
- form-action: מציין את כתובות ה-URL אליהן ניתן לשלוח שליחות טפסים.
- upgrade-insecure-requests: מורה לסוכן המשתמש לשדרג אוטומטית בקשות לא מאובטחות (HTTP) לבקשות מאובטחות (HTTPS).
- report-uri: מציין כתובת URL אליה הדפדפן צריך לשלוח דוחות על הפרות CSP. דירקטיבה זו נזנחה לטובת `report-to`.
- report-to: מציין שם של קבוצת דיווח המוגדרת בכותרת ה-`Report-To`, אליה הדפדפן צריך לשלוח דוחות על הפרות CSP.
מילות מפתח לרשימת מקורות של CSP
בתוך דירקטיבות CSP, ניתן להשתמש במילות מפתח של רשימת מקורות כדי להגדיר מקורות מורשים. הנה כמה מילות מפתח נפוצות:
- 'self': מאפשר משאבים מאותו מקור (סכימה ומארח) כמו המסמך.
- 'none': אוסר משאבים מכל המקורות.
- 'unsafe-inline': מאפשר שימוש בסקריפטים וסגנונות מוטבעים (לדוגמה, תגי <script> ותכונות style). יש להשתמש בזהירות יתרה מכיוון שזה מחליש משמעותית את הגנת ה-CSP מפני XSS.
- 'unsafe-eval': מאפשר שימוש בפונקציות הערכת קוד דינמיות כמו
eval()ו-Function(). יש להשתמש בזהירות יתרה מכיוון שזה מציג סיכוני אבטחה משמעותיים. - 'unsafe-hashes': מאפשר טיפול באירועים מוטבעים ספציפיים או תגי <style> התואמים ל-hash שצוין. דורש תמיכת דפדפן. יש להשתמש בזהירות.
- 'strict-dynamic': מציין כי האמון שניתן במפורש לסקריפט הקיים בסימון, על ידי צירופו עם nonce או hash, יופץ לכל הסקריפטים שנטענים על ידי סקריפט השורש הזה.
- data: מאפשר URI מסוג data: (לדוגמה, תמונות מוטבעות המקודדות ב-base64). יש להשתמש בזהירות.
- https:: מאפשר טעינת משאבים באמצעות HTTPS מכל דומיין.
- [hostname]: מאפשר משאבים מדומיין ספציפי (לדוגמה, example.com). ניתן גם לציין מספר פורט (לדוגמה, example.com:8080).
- [scheme]://[hostname]:[port]: URI מלא, המאפשר משאבים מהסכימה, המארח והפורט שצוינו.
דוגמאות מעשיות של CSP
בואו נסתכל על כמה דוגמאות מעשיות של כותרי CSP:
דוגמה 1: CSP בסיסי עם 'self'
מדיניות זו מאפשרת משאבים רק מאותו מקור:
Content-Security-Policy: default-src 'self'
דוגמה 2: התרת סקריפטים מדומיין ספציפי
מדיניות זו מאפשרת סקריפטים מהדומיין שלכם ומ-CDN מהימן:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
דוגמה 3: השבתת סקריפטים וסגנונות מוטבעים
מדיניות זו אוסרת סקריפטים וסגנונות מוטבעים, המהווה הגנה חזקה מפני XSS:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'
חשוב: השבתת סקריפטים מוטבעים דורשת ארגון מחדש של ה-HTML שלכם כדי להעביר סקריפטים מוטבעים לקבצים חיצוניים.
דוגמה 4: שימוש ב-Nonces לסקריפטים מוטבעים
אם עליכם להשתמש בסקריפטים מוטבעים, השתמשו ב-nonces (אסימונים אקראיים קריפטוגרפית, חד פעמיים) כדי להכניס לרשימה לבנה בלוקי סקריפט מוטבעים ספציפיים. זה מאובטח יותר מ-'unsafe-inline'. השרת חייב לייצר nonce ייחודי עבור כל בקשה ולכלול אותו גם בכותרת ה-CSP וגם בתג <script>.
Content-Security-Policy: default-src 'self'; script-src 'nonce-r4nd0mN0nc3'; style-src 'self'
<script nonce="r4nd0mN0nc3"> console.log('Inline script'); </script>
הערה: זכרו לייצר nonce חדש עבור כל בקשה. אל תעשו שימוש חוזר ב-nonces!
דוגמה 5: שימוש ב-Hashes לסגנונות מוטבעים
בדומה ל-nonces, ניתן להשתמש ב-hashes כדי להכניס לרשימה לבנה בלוקי <style> מוטבעים ספציפיים. זה נעשה על ידי יצירת hash SHA256, SHA384 או SHA512 של תוכן הסגנון.
Content-Security-Policy: default-src 'self'; style-src 'sha256-HASHEDSTYLES'
<style sha256="HASHEDSTYLES"> body { background-color: #f0f0f0; } </style>
הערה: hashes פחות גמישים מ-nonces מכיוון שכל שינוי בתוכן הסגנון יפסול את ה-hash.
דוגמה 6: דיווח על הפרות CSP
כדי לנטר הפרות CSP, השתמשו בדירקטיבת ה-report-uri או report-to:
Content-Security-Policy: default-src 'self'; report-to csp-endpoint;
יהיה עליכם גם להגדיר את כותרת ה-Report-To. כותרת ה-Report-To מגדירה קבוצת דיווח אחת או יותר, המציינות היכן וכיצד יש לשלוח דוחות.
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://example.com/csp-report"}]}
בדיקה ופריסה של CSP
יישום CSP דורש תכנון ובדיקה קפדניים. התחילו עם מדיניות מגבילה ושחררו אותה בהדרגה לפי הצורך. השתמשו בכותרת ה-Content-Security-Policy-Report-Only כדי לבדוק את המדיניות שלכם מבלי לחסום משאבים. כותרת זו מדווחת על הפרות מבלי לאכוף את המדיניות, ומאפשרת לכם לזהות ולתקן בעיות לפני פריסת המדיניות לייצור.
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint;
נתחו את הדוחות שנוצרו על ידי הדפדפן כדי לזהות הפרות כלשהן ולהתאים את המדיניות שלכם בהתאם. לאחר שאתם בטוחים שהמדיניות שלכם פועלת כהלכה, פרסו אותה באמצעות כותרת ה-Content-Security-Policy.
שיטות עבודה מומלצות עבור CSP
- התחילו עם default-src: תמיד הגדירו
default-srcכדי לבסס מדיניות בסיסית. - היו ספציפיים: השתמשו בדירקטיבות ספציפיות ובמילות מפתח של רשימת מקורות כדי להגביל את היקף המדיניות שלכם.
- הימנעו מ-'unsafe-inline' ו-'unsafe-eval': מילות מפתח אלו מחלישות משמעותית את CSP ויש להימנע מהן במידת האפשר.
- השתמשו ב-nonces או hashes לסקריפטים וסגנונות מוטבעים: אם עליכם להשתמש בסקריפטים או סגנונות מוטבעים, השתמשו ב-nonces או hashes כדי להכניס לרשימה לבנה בלוקי קוד ספציפיים.
- נטרו הפרות CSP: השתמשו בדירקטיבת ה-
report-uriאוreport-toכדי לנטר הפרות CSP ולהתאים את המדיניות שלכם בהתאם. - בחנו ביסודיות: השתמשו בכותרת ה-
Content-Security-Policy-Report-Onlyכדי לבדוק את המדיניות שלכם לפני פריסתה לייצור. - חזרו ושכללו: CSP אינו תצורה חד פעמית. נטרו ושכללו באופן רציף את המדיניות שלכם כדי להתאים לשינויים ביישום שלכם ונוף האיומים.
מהו שיתוף משאבים חוצי מקורות (CORS)?
Cross-Origin Resource Sharing (CORS) הוא מנגנון המאפשר לדפי אינטרנט ממקור אחד (דומיין) לגשת למשאבים ממקור אחר. כברירת מחדל, דפדפנים אוכפים מדיניות Same-Origin, המונעת מסקריפטים לבצע בקשות למקור שונה מזה שממנו הגיע הסקריפט. CORS מספק דרך לשחרר באופן סלקטיבי הגבלה זו, ומאפשר בקשות חוצות מקורות לגיטימיות תוך הגנה מפני התקפות זדוניות.
הבנת מדיניות Same-Origin
מדיניות Same-Origin היא מנגנון אבטחה בסיסי המונע מסקריפט זדוני באתר אינטרנט אחד לגשת לנתונים רגישים באתר אינטרנט אחר. מקור מוגדר על ידי הסכימה (פרוטוקול), המארח (דומיין) והפורט. לשתי כתובות URL יש את אותו מקור אם ורק אם יש להן אותה סכימה, מארח ופורט.
לדוגמה:
https://www.example.com/app1/index.htmlול-https://www.example.com/app2/index.htmlיש את אותו מקור.- ל-
https://www.example.com/index.htmlול-http://www.example.com/index.htmlיש מקורות שונים (סכימה שונה). - ל-
https://www.example.com/index.htmlול-https://sub.example.com/index.htmlיש מקורות שונים (מארח שונה). - ל-
https://www.example.com:8080/index.htmlול-https://www.example.com:80/index.htmlיש מקורות שונים (פורט שונה).
כיצד פועל CORS
כאשר דף אינטרנט מבצע בקשה חוצת מקורות, הדפדפן שולח תחילה בקשת "preflight" לשרת. בקשת ה-preflight משתמשת בשיטת HTTP OPTIONS וכוללת כותרות המציינות את שיטת ה-HTTP והכותרות שהבקשה בפועל תשתמש בהן. השרת מגיב אז עם כותרות המציינות אם הבקשה חוצת המקורות מותרת.
אם השרת מאפשר את הבקשה, הוא כולל את כותרת ה-Access-Control-Allow-Origin בתגובה. כותרת זו מציינת את המקורות המורשים לגשת למשאב. הדפדפן ממשיך אז עם הבקשה בפועל. אם השרת אינו מאפשר את הבקשה, הוא אינו כולל את כותרת ה-Access-Control-Allow-Origin, והדפדפן חוסם את הבקשה.
כותרות CORS: מבט מפורט
CORS מסתמך על כותרי HTTP כדי לתקשר בין הדפדפן לשרת. הנה כותרי ה-CORS העיקריים:
- Access-Control-Allow-Origin: מציין את המקורות המורשים לגשת למשאב. כותרת זו יכולה להכיל מקור ספציפי (לדוגמה,
https://www.example.com), תו כללי (*), אוnull. שימוש ב-*מאפשר בקשות מכל מקור, מה שלרוב אינו מומלץ מסיבות אבטחה. שימוש ב-`null` מתאים רק ל"תגובות אטומות" כמו כאשר המשאב נשלף באמצעות פרוטוקול `file://` או URI מסוג data. - Access-Control-Allow-Methods: מציין את שיטות ה-HTTP המותרות לבקשה חוצת המקורות (לדוגמה,
GET, POST, PUT, DELETE). - Access-Control-Allow-Headers: מציין את כותרי ה-HTTP המותרים בבקשה חוצת המקורות. זה חשוב לטיפול בכותרות מותאמות אישית.
- Access-Control-Allow-Credentials: מציין אם הדפדפן צריך לכלול אישורים (לדוגמה, קובצי Cookie, כותרי הרשאה) בבקשה חוצת המקורות. כותרת זו חייבת להיות מוגדרת ל-
trueכדי לאפשר אישורים. - Access-Control-Expose-Headers: מציין אילו כותרות יכולות להיחשף ללקוח. כברירת מחדל, רק סט מוגבל של כותרות נחשף.
- Access-Control-Max-Age: מציין את משך הזמן המקסימלי (בשניות) שהדפדפן יכול לשמור במטמון את בקשת ה-preflight.
- Origin: זוהי כותרת בקשה שנשלחת על ידי הדפדפן כדי לציין את מקור הבקשה.
- Vary: כותרת HTTP כללית, אך חשובה עבור CORS. כאשר `Access-Control-Allow-Origin` נוצר באופן דינמי, יש לכלול את כותרת ה-`Vary: Origin` בתגובה כדי להורות למנגנוני מטמון שהתגובה משתנה בהתבסס על כותרת הבקשה `Origin`.
דוגמאות מעשיות של CORS
בואו נסתכל על כמה דוגמאות מעשיות של תצורות CORS:
דוגמה 1: התרת בקשות ממקור ספציפי
תצורה זו מאפשרת בקשות רק מ-https://www.example.com:
Access-Control-Allow-Origin: https://www.example.com
דוגמה 2: התרת בקשות מכל מקור (לא מומלץ)
תצורה זו מאפשרת בקשות מכל מקור. יש להשתמש בזהירות מכיוון שהיא עלולה להציג סיכוני אבטחה:
Access-Control-Allow-Origin: *
דוגמה 3: התרת שיטות וכותרות ספציפיות
תצורה זו מאפשרת שיטות GET, POST ו-PUT, ואת הכותרות Content-Type ו-Authorization:
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
דוגמה 4: התרת אישורים
כדי לאפשר אישורים (לדוגמה, קובצי Cookie), עליכם להגדיר את Access-Control-Allow-Credentials ל-true ולציין מקור ספציפי (אינכם יכולים להשתמש ב-* כאשר מאפשרים אישורים):
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
כמו כן, עליכם להגדיר credentials: 'include' בבקשת ה-fetch/XMLHttpRequest של JavaScript שלכם.
fetch('https://api.example.com/data', {
credentials: 'include'
})
בקשות Preflight של CORS
עבור סוגים מסוימים של בקשות חוצות מקורות (לדוגמה, בקשות עם כותרות מותאמות אישית או שיטות שאינן GET, HEAD, או POST עם Content-Type של application/x-www-form-urlencoded, multipart/form-data, או text/plain), הדפדפן שולח בקשת preflight באמצעות שיטת OPTIONS. השרת חייב להגיב לבקשת ה-preflight עם כותרי CORS המתאימים כדי לציין אם הבקשה בפועל מותרת.
הנה דוגמה לבקשת preflight ותגובה:
בקשת Preflight (OPTIONS):
OPTIONS /data HTTP/1.1
Origin: https://www.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
תגובת Preflight (200 OK):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
כותרת ה-Access-Control-Max-Age מציינת כמה זמן הדפדפן יכול לשמור במטמון את תגובת ה-preflight, מה שמפחית את מספר בקשות ה-preflight.
CORS ו-JSONP
JSON with Padding (JSONP) היא טכניקה ישנה יותר לעקיפת מדיניות ה-Same-Origin. עם זאת, ל-JSONP יש סיכוני אבטחה משמעותיים ויש להימנע ממנה לטובת CORS. JSONP מסתמכת על הזרקת תגי <script> לדף, שיכולים לבצע קוד שרירותי. CORS מספקת דרך מאובטחת וגמישה יותר לטפל בבקשות חוצות מקורות.
שיטות עבודה מומלצות עבור CORS
- הימנעו משימוש ב-*: הימנעו משימוש בתו הכללי (*) בכותרת ה-
Access-Control-Allow-Origin, מכיוון שהוא מאפשר בקשות מכל מקור. במקום זאת, ציינו את המקורות הספציפיים המורשים לגשת למשאב. - היו ספציפיים עם שיטות וכותרות: ציינו את שיטות ה-HTTP והכותרות המדויקות המותרות בכותרות ה-
Access-Control-Allow-Methodsו-Access-Control-Allow-Headers. - השתמשו ב-Access-Control-Allow-Credentials בזהירות: אפשרו את
Access-Control-Allow-Credentialsרק אם אתם צריכים לאפשר אישורים (לדוגמה, קובצי Cookie) בבקשות חוצות מקורות. היו מודעים להשלכות האבטחה של התרת אישורים. - אבטחו את בקשות ה-preflight שלכם: ודאו שהשרת שלכם מטפל כראוי בבקשות preflight ומחזיר את כותרי ה-CORS הנכונים.
- השתמשו ב-HTTPS: השתמשו תמיד ב-HTTPS הן עבור המקור והן עבור המשאבים אליהם אתם ניגשים חוצה מקורות. זה עוזר להגן מפני התקפות אדם בתווך.
- Vary: Origin: אם אתם מייצרים באופן דינמי את כותרת ה-`Access-Control-Allow-Origin`, תמיד כללו את כותרת ה-`Vary: Origin` כדי למנוע בעיות מטמון.
CSP ו-CORS בפועל: גישה משולבת
בעוד ש-CSP ו-CORS שניהם מטפלים בחששות אבטחה, הם פועלים בשכבות שונות ומספקים הגנה משלימה. CSP מתמקד במניעת טעינת תוכן זדוני על ידי הדפדפן, בעוד CORS מתמקד בשליטה אילו מקורות יכולים לגשת למשאבים בשרת שלכם.
על ידי שילוב CSP ו-CORS, אתם יכולים ליצור עמדת אבטחה חזקה יותר עבור יישומי האינטרנט שלכם. לדוגמה, אתם יכולים להשתמש ב-CSP כדי להגביל את המקורות מהם ניתן לטעון סקריפטים, וב-CORS כדי לשלוט אילו מקורות יכולים לגשת לנקודות הקצה של ה-API שלכם.
דוגמה: אבטחת API עם CSP ו-CORS
נניח שיש לכם API המתארח ב-https://api.example.com שאתם רוצים שיהיה נגיש רק מ-https://www.example.com. תוכלו להגדיר את השרת שלכם להחזיר את הכותרות הבאות:
כותרי תגובת API (https://api.example.com):
Access-Control-Allow-Origin: https://www.example.com
Content-Type: application/json
ותוכלי להגדיר את אתר האינטרנט שלכם (https://www.example.com) להשתמש בכותרת ה-CSP הבאה:
Content-Security-Policy: default-src 'self'; script-src 'self'; connect-src 'self' https://api.example.com;
מדיניות CSP זו מאפשרת לאתר לטעון סקריפטים ולהתחבר ל-API, אך מונעת ממנו לטעון סקריפטים או להתחבר לדומיינים אחרים.
מסקנה
Content Security Policy (CSP) ו-Cross-Origin Resource Sharing (CORS) הם כלים חיוניים לחיזוק אבטחת יישומי צד הלקוח שלכם. על ידי הגדרה קפדנית של CSP ו-CORS, תוכלו להפחית משמעותית את הסיכון להתקפות XSS, התקפות הזרקת נתונים ופגיעויות אבטחה אחרות. זכרו להתחיל עם מדיניות מגבילה, לבדוק ביסודיות, ולנטר ולשכלל באופן רציף את התצורה שלכם כדי להתאים לשינויים ביישום שלכם ולנוף האיומים המתפתח. על ידי תעדוף אבטחת צד הלקוח, תוכלו להגן על המשתמשים שלכם ולהבטיח את שלמות יישומי האינטרנט שלכם בעולם הדיגיטלי המורכב יותר ויותר של ימינו.