Content Security Policy

מייק ווסט
ג'ו מדלי
ג'ו מדלי

מודל האבטחה של האינטרנט מבוסס על מדיניות המקור הזהה. לקוד מ-https://mybank.com צריכה להיות גישה רק לנתונים של https://mybank.com, ובטח שלא לאפשר גישה ל-https://evil.example.com. כל מקור מבודד משאר האינטרנט, וכך למפתחים ארגז חול בטוח ליצירה ולהפעלה. בתיאוריה, זה מבריק לגמרי. בפועל, תוקפים מצאו דרכים מתוחכמות להערים על המערכת.

התקפות של סקריפטים חוצי-אתרים (XSS), למשל, עוקפים את אותה מדיניות מקור על ידי הטעיית האתר כך שיספק קוד זדוני יחד עם התוכן המיועד. זו בעיה ענקית, כי דפדפנים סומכים על כל הקוד שמופיע בדף כחלק לגיטימי ממקור האבטחה של הדף. XSS Cheat Sheet הוא חתך ישן אך מייצג של השיטות שבהן תוקף עלול להשתמש כדי להפר את האמון הזה על ידי החדרת קוד זדוני. אם תוקף מחדיר בהצלחה קוד כלשהו, זה כמעט נגמר: נתוני סשנים של משתמשים נמצאים בסיכון, ומידע שצריך לשמור בסודיות נזרק ל-The Bad Guys. כמובן שנרצה למנוע זאת אם אפשר.

בסקירה הכללית הזו מודגשים אמצעי הגנה שיכולים לצמצם משמעותית את הסיכון ואת ההשפעה של מתקפות XSS בדפדפנים מודרניים: Content Security Policy (CSP).

אמ;לק

  • משתמשים ברשימות היתרים כדי לומר ללקוח מה מותר ומה אסור.
  • למידע נוסף על ההוראות הזמינות.
  • למד מהן מילות המפתח שלהן.
  • קוד בתוך השורה ו-eval() נחשבים לקודים מזיקים.
  • עליך לדווח לשרת שלך על הפרות מדיניות לפני האכיפה שלהן.

רשימות היתרים של מקורות

התקפות XSS שמנוצלות הן חוסר היכולת של הדפדפן להבחין בין סקריפט ששייך לאפליקציה לבין סקריפט שהוחדר בזדון על ידי צד שלישי. לדוגמה, כפתור Google +1 שבתחתית הדף הזה טוען ומפעיל קוד מ-https://apis.google.com/js/plusone.js בהקשר של המקור של הדף הזה. אנחנו סומכים על הקוד הזה, אבל אנחנו לא יכולים לצפות שהדפדפן יבין בעצמו שהקוד מ-apis.google.com הוא מדהים, ואילו קוד מ-apis.evil.example.com כנראה לא. הדפדפן בשמחה מוריד ומפעיל כל קוד שדף מבקש, ללא קשר למקור.

במקום לסמוך באופן עיוור על כל ששרת מספק, ב-CSP מוגדרת כותרת ה-HTTP Content-Security-Policy, שמאפשרת ליצור רשימת היתרים של מקורות של תוכן מהימן. היא מנחה את הדפדפן להפעיל או לעבד משאבים רק מהמקורות האלה. גם אם תוקף יכול למצוא חור שבאמצעותו ניתן להחדיר סקריפט, הסקריפט לא יתאים לרשימת ההיתרים ולכן לא יופעל.

אנחנו סומכים על apis.google.com שיספק קוד תקין, ואנחנו סומכים על כך שנעשה את אותו הדבר, לכן נגדיר מדיניות שמאפשרת לסקריפט לפעול רק כאשר הוא מגיע מאחד משני המקורות האלה:

Content-Security-Policy: script-src 'self' https://apis.google.com

פשוט, נכון? כמו שבטח ניחשת, script-src היא הוראה ששולטת בקבוצת הרשאות שקשורות לסקריפט בדף ספציפי. הגדרנו את 'self' כמקור חוקי אחד לסקריפט ואת https://apis.google.com כמקור אחר. הדפדפן מוריד ומפעיל בקפדנות JavaScript מ-apis.google.com ב-HTTPS, וגם מהמקור של הדף הנוכחי.

שגיאת מסוף: המערכת לא הצליחה לטעון את הסקריפט 'http://evil.example.com/evil.js' מכיוון שהוא מפר את ההוראה הבאה של Content Security Policy: script-src 'self' https://apis.google.com

כשהמדיניות הזו מוגדרת, הדפדפן פשוט מקפיץ הודעת שגיאה במקום לטעון סקריפט מכל מקור אחר. כשתוקף מתוחכם מצליח להחדיר קוד לאתר, הוא יקבל הודעת שגיאה במקום בהצלחה.

המדיניות חלה על מגוון רחב של משאבים

על אף שמשאבי סקריפטים הם סיכוני האבטחה הברורים ביותר, CSP מספק קבוצה עשירה של הוראות מדיניות שמאפשרות שליטה פרטנית למדי על המשאבים שדף יכול להיטען. כבר ראיתם את script-src, אז הקונספט צריך להיות ברור.

בואו נסתכל במהירות על שאר ההוראות של המשאבים. הרשימה הבאה מייצגת את מצב ההוראות נכון לרמה 2. פורסם מפרט של רמה 3, אבל לא מיושם ברובו בדפדפנים הראשיים.

  • base-uri מגבילה את כתובות ה-URL שיכולות להופיע ברכיב <base> של הדף.
  • ב-child-src מפורטות כתובות ה-URL של עובדים ושל תוכן המסגרות המוטמעות. לדוגמה: child-src https://youtube.com יאפשר הטמעה של סרטונים מ-YouTube אבל לא ממקורות אחרים.
  • הקוד connect-src מגביל את המקורות שאפשר להתחבר אליהם (דרך XHR, WebSockets ו-EventSource).
  • font-src מציין את המקורות שיכולים להציג גופני אינטרנט. אפשר להפעיל את גופני האינטרנט של Google באמצעות font-src https://themes.googleusercontent.com.
  • התג form-action כולל נקודות קצה תקינות לשליחה מתגי <form>.
  • frame-ancestors מציין את המקורות שיכולים להטמיע את הדף הנוכחי. ההוראה הזו חלה על התגים <frame>, <iframe>, <embed> וגם <applet>. לא ניתן להשתמש בהוראה הזו בתגי <meta>, והיא חלה רק על משאבים שאינם HTML.
  • המודל frame-src הוצא משימוש ברמה 2, אבל שוחזר ברמה 3. אם הוא לא מופיע, הוא עדיין יחזור להיות child-src כמו קודם.
  • img-src מגדיר את המקורות שמהם ניתן לטעון את התמונות.
  • ההגדרה media-src מגבילה את המקורות שמורשים להעביר וידאו ואודיו.
  • object-src מאפשר שליטה על Flash ויישומי פלאגין אחרים.
  • המדיניות plugin-types מגבילה את סוגי יישומי הפלאגין שדף יכול להפעיל.
  • ב-report-uri מציינים את כתובת ה-URL שאליה הדפדפן שולח דוחות במקרה של הפרה של מדיניות אבטחת תוכן. לא ניתן להשתמש בהוראה הזו בתגי <meta>.
  • style-src הוא המקביל של script-src לגיליונות סגנונות.
  • upgrade-insecure-requests מורה לסוכני המשתמש לשכתב סכימות של כתובות URL, ולשנות את HTTP ל-HTTPS. ההנחיה הזו מיועדת לאתרים עם מספר גדול של כתובות URL ישנות שצריך לשכתב.
  • worker-src היא הוראה ב-CSP ברמה 3 שמגבילה את כתובות ה-URL שעשויות להיטען כ-worker, כ-Shared Worker או כ-service worker. החל מיולי 2017, יש הגבלות על הטמעות של ההנחיה הזו.

כברירת מחדל, ההנחיות פתוחות לכולם. אם לא מגדירים מדיניות ספציפית להנחיה, למשל font-src, ההנחיה תפעל כברירת מחדל כפי שציינתם את * כמקור החוקי (לדוגמה, אפשר לטעון גופנים מכל מקום, ללא הגבלה).

אפשר לשנות את התנהגות ברירת המחדל הזו על ידי ציון הוראה של default-src. ההוראה הזו מגדירה את ברירות המחדל של רוב ההנחיות שלא צוינו. באופן כללי, הכלל הזה חל על כל הוראה שמסתיימת ב--src. אם המדיניות default-src מוגדרת לערך https://example.com ולא צוין הוראת font-src, אפשר לטעון גופנים מ-https://example.com ולא בשום מקום אחר. בדוגמאות הקודמות שלנו צוין רק script-src, כך שאפשר לטעון תמונות, גופנים וכו' מכל מקור.

ההנחיות הבאות לא משתמשות ב-default-src כחלופה. חשוב לזכור שאם לא תגדירו אותן, זהו אישור של כל דבר.

  • base-uri
  • form-action
  • frame-ancestors
  • plugin-types
  • report-uri
  • sandbox

אפשר להשתמש בכמה או מעט מההנחיות האלה, לפי הצורך, בהתאם לאפליקציה הספציפית שלכם. פשוט צריך לרשום כל אחת מההנחיות בכותרת ה-HTTP ולהפריד ביניהן עם נקודה-פסיק. חשוב לפרט בהוראת single את כל המשאבים הנדרשים מסוג מסוים. אם כותבים משהו כמו script-src https://host1.com; script-src https://host2.com, המערכת פשוט תתעלם מההנחיה השנייה. למשל, כאן תציינו בצורה נכונה ששני המקורות חוקיים:

script-src https://host1.com https://host2.com

לדוגמה, אם יש לכם אפליקציה שטוענת את כל המשאבים שלה מרשת להעברת תוכן (למשל, https://cdn.example.net), ואתם יודעים שלא צריך תוכן ממוסגר או יישומי פלאגין, המדיניות יכולה להיראות כך:

Content-Security-Policy: default-src https://cdn.example.net; child-src 'none'; object-src 'none'

פרטי ההטמעה

הכותרות של X-WebKit-CSP ו-X-Content-Security-Policy יופיעו במדריכים שונים באינטרנט. מעכשיו צריך להתעלם מהכותרות הקידומות האלה. דפדפנים מודרניים (למעט IE) תומכים בכותרת Content-Security-Policy ללא קידומת. זו הכותרת שבה צריך להשתמש.

המדיניות מוגדרת לכל דף בנפרד, בלי קשר לכותרת העליונה: צריך לשלוח את כותרת ה-HTTP יחד עם כל תגובה שאתם רוצים להבטיח שתהיה מוגנת. כך מתאפשרת גמישות רבה, כי אתם יכולים לחדד את המדיניות לדפים ספציפיים על סמך הצרכים הספציפיים שלהם. ייתכן שבקבוצה אחת של דפים באתר שלך יש לחצן 1+, בעוד שבקבוצות אחרות אין: תוכלו לאפשר טעינה של קוד הלחצן רק בעת הצורך.

רשימת המקורות בכל הנחיה היא גמישה. אפשר לציין מקורות לפי סכמה (data:, https:) או לפי ספציפיות, החל משם מארח בלבד (example.com, שתואם כל מקור במארח הזה: כל סכימה, כל יציאה) ל-URI שמוגדר במלואו (https://example.com:443, שתואם רק ל-HTTPS, ל-example.com בלבד ורק ליציאה 443). אפשר להשתמש בתווים כלליים לחיפוש, אבל רק בסכמה, ביציאה או במיקום השמאלי ביותר של שם המארח: *://*.example.com:* יתאים לכל תתי-הדומיין של example.com (אבל לא example.com עצמו), בכל סכמה, בכל יציאה.

רשימת המקור מקבלת גם ארבע מילות מפתח:

  • 'none', כפי שציפיתם, לא תואם בכלל.
  • 'self' תואם למקור הנוכחי, אך לא לתת-הדומיינים שלו.
  • 'unsafe-inline' מאפשר JavaScript ו-CSS מוטבעים. (נרחיב על כך עוד מעט).
  • 'unsafe-eval' מאפשר מנגנוני טקסט ל-JavaScript כמו eval. (נתייחס גם לזה.)

מילות המפתח האלה צריכות מירכאות בודדות. לדוגמה, script-src 'self' (עם מירכאות) מאשר הפעלה של JavaScript מהמארח הנוכחי; script-src self (ללא מירכאות) מאפשר JavaScript משרת בשם "self" (ולא מהמארח הנוכחי), וסביר להניח שלא זו הייתה כוונתך.

הרצה בארגז חול

יש עוד הנחיה אחת שכדאי לדבר עליה: sandbox. התצוגה הזו שונה במקצת משיטות אחרות שבדקנו, מפני שהיא מגבילה את הפעולות שהדף יכול לבצע ולא את המשאבים שהדף יכול לטעון. אם ההוראה sandbox קיימת, המערכת תתייחס לדף כאילו הוא נטען בתוך <iframe> עם מאפיין sandbox. למצב כזה יכולות להיות מגוון רחב של השפעות על הדף: אילוץ הדף למקור ייחודי, כמו גם מניעה של שליחת טפסים. המאמר הזה קצת מעבר להיקף המאמר, אבל אפשר למצוא פרטים מלאים על מאפיינים חוקיים של הרצה בארגז חול בקטע 'Sandboxing' במפרט של HTML5.

המטא תג

מנגנון המסירה המועדף של CSP הוא כותרת HTTP. עם זאת, כדאי להגדיר מדיניות בדף ישירות בתגי העיצוב. ניתן לעשות זאת באמצעות תג <meta> עם מאפיין http-equiv:

<meta
  http-equiv="Content-Security-Policy"
  content="default-src https://cdn.example.net; child-src 'none'; object-src 'none'"
/>

אי אפשר להשתמש באפליקציה הזו עבור frame-ancestors, report-uri או sandbox.

קוד בתוך השורה נחשב למזיק

צריך להיות ברור שתוכנית CSP מבוססת על המקורות ברשימת ההיתרים, כי זו דרך חד-משמעית להנחות את הדפדפן להתייחס לקבוצות משאבים מסוימות בצורה מקובלת ולדחות את השאר. עם זאת, רשימות היתרים מבוססות-מקור לא פותרות את האיום הגדול ביותר של מתקפות XSS: הזרקת סקריפט מוטבע. אם תוקף יכול להחדיר תג סקריפט שמכיל ישירות מטען ייעודי (payload) זדוני (<script>sendMyDataToEvilDotCom();</script>), אין לדפדפן מנגנון שבאמצעותו אפשר להבדיל בינו לבין תג של סקריפט מוטבע חוקי. CSP פותרת את הבעיה הזו על ידי חסימה מוחלטת של סקריפט מוטבע: זו הדרך היחידה לדעת בוודאות.

החסימה כוללת לא רק סקריפטים שמוטמעים ישירות בתגי script, אלא גם גורמים מטפלים באירועים מוטבעים וכתובות URL של javascript:. צריך להעביר את התוכן של תגי script לקובץ חיצוני, ולהחליף javascript: כתובות URL ו-<a ... onclick="[JAVASCRIPT]"> בקריאות מתאימות של addEventListener(). לדוגמה, אפשר לשכתב את הקטע הבא מתוך:

<script>
  function doAmazingThings() {
    alert('YOU AM AMAZING!');
  }
</script>
<button onclick="doAmazingThings();">Am I amazing?</button>

למשהו יותר כמו:

<!-- amazing.html -->
<script src="amazing.js"></script>
<button id="amazing">Am I amazing?</button>

<div style="clear:both;"></div>
// amazing.js
function doAmazingThings() {
  alert('YOU AM AMAZING!');
}
document.addEventListener('DOMContentLoaded', function () {
  document.getElementById('amazing').addEventListener('click', doAmazingThings);
});

לקוד המשוכתב יש כמה יתרונות מעל ומעבר לעבודה טובה עם CSP. כבר עכשיו השיטה הזו מומלצת, ללא קשר לשימוש שלכם ב-CSP. מוטבעת JavaScript משלבת מבנה והתנהגות בדיוק באופן שבו לא אמורים לעשות זאת. משאבים חיצוניים עוזרים לדפדפנים לשמור במטמון, מבינים יותר למפתחים ויכולים להידרש ולהקטין אותם. תוכלו לכתוב קוד טוב יותר אם תבצעו את העברת הקוד למשאבים חיצוניים.

המערכת מתייחסת לסגנון בתוך השורה באותו אופן: צריך לאחד את המאפיין style ואת התגים style לגיליונות סגנונות חיצוניים כדי להגן מפני מגוון שיטות חכמות של זליגת נתונים שאפשר להפעיל ב-CSS.

אם חייבים להיות לכם סקריפט וסגנון מוטבעים, אפשר להפעיל אותם על ידי הוספה של 'unsafe-inline' כמקור מותר בהנחיה script-src או style-src. אתם יכולים גם להשתמש בגיבובים (hash) או בצפנים חד-פעמיים (ראו בהמשך), אבל לא מומלץ לעשות זאת. חסימה של סקריפט מוטבע היא הניצחון הגדול ביותר באבטחה של CSP, וחסימת סגנון מוטבע מקשה גם על האפליקציה שלכם. אמנם יש קצת מאמץ מראש כדי לוודא שהכול יפעל כמו שצריך אחרי שמעבירים את כל הקוד מהשורה, אבל זה יתרון משתלם.

אם אתם חייבים להשתמש בה לגמרי

ב-CSP ברמה 2 פועלת תאימות לאחור לסקריפטים מוטבעים, כי היא מאפשרת להוסיף סקריפטים ספציפיים מוטבעים לרשימת ההיתרים באמצעות קוד חד-פעמי (hash) קריפטוגרפי (מספר שנעשה בו שימוש פעם אחת) או גיבוב (hash). למרות שזה עלול להיות מסורבל, הוא שימושי במקרה הצורך.

כדי להשתמש צופן חד-פעמי (nonce), צריך להוסיף לתג הסקריפט מאפיין חד-פעמי (nonce). הערך שלו חייב להתאים לאחת מהאפשרויות ברשימת המקורות המהימנים. לדוגמה:

<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
  // Some inline code I can't remove yet, but need to asap.
</script>

בשלב הזה צריך להוסיף את צופן חד-פעמי (nonce) להוראה script-src שמצורפת למילת המפתח nonce-.

Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'

חשוב לזכור שצריך ליצור מחדש צפנים חד-פעמיים לכל בקשה לדף, ושלא ניתן יהיה לנחש אותם.

גיבובים פועלים באותה צורה. במקום להוסיף קוד לתג הסקריפט, עליכם ליצור גיבוב SHA של הסקריפט עצמו ולהוסיף אותו להוראה script-src. לדוגמה, נניח שהדף מכיל:

<script>
  alert('Hello, world.');
</script>

המדיניות שלכם תכיל את המידע הבא:

Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='

יש כמה דברים שכדאי לשים לב אליהם. הקידומת sha*- מציינת את האלגוריתם שיוצר את הגיבוב. בדוגמה שלמעלה, נעשה שימוש ב-sha256-. ב-CSP יש תמיכה גם ב-sha384- וב-sha512-. כשיוצרים את הגיבוב, חשוב לא לכלול את תגי <script>. צריך גם להשתמש באותיות רישיות וברווחים, כולל רווחים לבנים בתחילת הטקסט או בסופו.

חיפוש ב-Google שיעזור לכם ליצור גיבובי SHA יוביל אתכם לפתרונות בכל מספר של שפות. ב-Chrome בגרסה 40 ואילך, תוכלו לפתוח את כלי הפיתוח ולטעון מחדש את הדף. כרטיסיית המסוף תכיל הודעות שגיאה עם גיבוב sha256 הנכון לכל אחד מהסקריפטים המוטבעים.

גם הערכה

גם אם התוקפים לא מצליחים להחדיר סקריפט באופן ישיר, הם עלולים להטעות את האפליקציה ולגרום להם להמיר טקסט שכבר קיים ל-JavaScript ניתן להפעלה, ולהפעיל אותו בשמו. eval(), הפונקציה new Function(), setTimeout([string], ...) ו-setInterval([string], ...) הם וקטורים שדרכם הטקסט שהוחדר עלול להפעיל משהו זדוני בלתי צפוי. תגובת ברירת המחדל של CSP לסיכון הזה היא לחסום לחלוטין את כל הווקטורים האלה.

יש לזה כמה השפעות על אופן הבנייה של אפליקציות:

  • צריך לנתח את קובץ ה-JSON דרך ה-JSON.parse המובנה, ולא להסתמך על eval. פעולות JSON מקוריות זמינות בכל דפדפן מ-IE8, והן בטוחות לגמרי.
  • צריך לשכתב את כל השיחות ל-setTimeout או ל-setInterval שאתם מבצעים כרגע באמצעות פונקציות מוטבעות ולא מחרוזות. לדוגמה:
setTimeout("document.querySelector('a').style.display = 'none';", 10);

ייכתב כך:

setTimeout(function () {
  document.querySelector('a').style.display = 'none';
}, 10);
  • יש להימנע מיצירת תבניות מוטבעות בזמן ריצה: הרבה ספריות תבניות משתמשות ב-new Function() באופן חופשי כדי להאיץ את יצירת התבניות בזמן ריצה. זה יישום מעולה של תכנות דינמי, אבל הוא כולל סיכון של בדיקת טקסט זדוני. חלק מתבניות ה-framework תומכות ב-CSP מהרגע הראשון, אבל כשאין eval, הן ממשיכות להשתמש במנתח נתונים מתקדם. הוראת ng-csp של AnngularJS היא דוגמה טובה לכך.

עם זאת, אפשרות טובה יותר היא להשתמש בשפה ליצירת תבניות שמציעה הידור מראש (למשל, כן). הידור מראש של התבניות יכול להפוך את חוויית המשתמש למהירה אף יותר מההטמעה המהירה ביותר בסביבת זמן ריצה, והיא גם בטוחה יותר. אם הערכה וקטעי הטקסט שלה ב-JavaScript חיוניים לאפליקציה שלך, ניתן להפעיל אותם על ידי הוספת 'unsafe-eval' כמקור מותר בהוראה script-src, אבל מאוד לא מומלץ לעשות זאת. חסימת היכולת לבצע מחרוזות מקשה מאוד על תוקפים להפעיל קוד לא מורשה באתר.

דוחות

היכולת של CSP לחסום משאבים לא מהימנים בצד הלקוח מועילה מאוד למשתמשים, אבל מאוד מועיל לשלוח התראה כלשהי לשרת כדי שתוכלו לזהות ולדחס כל באגים שמאפשרים הזרקה זדונית מלכתחילה. לשם כך, תוכלו להורות לדפדפן POST דוחות הפרה בפורמט JSON למיקום שצוין בהוראת report-uri.

Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;

הדוחות האלה ייראו בערך כך:

{
  "csp-report": {
    "document-uri": "http://example.org/page.html",
    "referrer": "http://evil.example.com/",
    "blocked-uri": "http://evil.example.com/evil.js",
    "violated-directive": "script-src 'self' https://apis.google.com",
    "original-policy": "script-src 'self' https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser"
  }
}

החלק הזה מכיל מידע רב שיעזור לך לאתר את הסיבה הספציפית להפרה, כולל הדף שבו התרחשה ההפרה (document-uri), הגורם המפנה של הדף (שימו לב שבניגוד לשדה בכותרת ה-HTTP, המפתח לא מאוית בצורה שגויה), המשאב שהפר את מדיניות הדף (blocked-uri), ההוראה הספציפית שהוא הפר (violated-directive) והמדיניות המלאה של הדף (original-policy).

דוח בלבד

אם רק התחלתם להשתמש ב-CSP, כדאי להעריך את המצב הנוכחי של האפליקציה לפני שמשיקים מדיניות דרקונית למשתמשים. בתור אבן דרך לפריסה מלאה, תוכלו לבקש מהדפדפן לעקוב אחרי המדיניות, לדווח על הפרות אבל לא לאכוף את ההגבלות. במקום לשלוח את הכותרת Content-Security-Policy, צריך לשלוח את הכותרת Content-Security-Policy-Report-Only.

Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;

המדיניות שצוינה במצב דיווח בלבד לא תחסום משאבים מוגבלים, אבל יישלחו דוחות על הפרות למיקום שציינתם. אפשר אפילו לשלוח את שתי הכותרות, תוך אכיפה של מדיניות אחת תוך מעקב אחר מדיניות אחרת. זוהי דרך מצוינת להעריך את ההשפעה של שינויים ב-CSP של האפליקציה: הפעילו דיווח על מדיניות חדשה, עקבו אחרי הדיווחים על הפרות ותקנו באגים שאותרו. כשתהיו מרוצים מההשפעה, התחילו לאכוף את המדיניות החדשה.

שימוש בעולם האמיתי

אפשר להשתמש ב-CSP 1 ב-Chrome, ב-Safari וב-Firefox, אבל התמיכה ב-IE 10 מוגבלת מאוד. אתם יכולים להציג פרטים נוספים בכתובת caniuse.com. רמה 2 של CSP זמינה ב-Chrome מגרסה 40. אתרים גדולים כמו Twitter ו-Facebook פרסו את הכותרת (המקרה לדוגמה של Twitter – שווה קריאה), והוא כבר מוכן כדי להתחיל לפרוס באתרים שלכם.

השלב הראשון ביצירת מדיניות לאפליקציה הוא להעריך את המשאבים שאתם טוענים בפועל. אם תחשבו להבנת האופן שבו כל הדברים מקובצים באפליקציה שלכם, תוכלו להגדיר מדיניות על סמך הדרישות האלה. נסביר עכשיו על כמה תרחישים נפוצים ונראה איך נוכל לתמוך בהם במסגרת גבולות ההגנה של CSP.

תרחיש לדוגמה מס' 1: ווידג'טים של מדיה חברתית

  • לחצן 1+ של Google כולל סקריפט מ-https://apis.google.com, ומטמיע <iframe> מ- https://plusone.google.com. כדי להטמיע את הלחצן, נדרשת מדיניות שכוללת את שני המקורות האלה. מדיניות מינימלית תהיה script-src https://apis.google.com; child-src https://plusone.google.com. צריך גם לוודא שקטע ה-JavaScript ש-Google מספקת נשלף לתוך קובץ JavaScript חיצוני. אם הייתה לכם מדיניות מבוססת-רמה 1 שהשתמשתם בה ב-frame-src רמה 2, היה עליכם לשנות אותה ל-child-src. אין יותר צורך לעשות זאת ב-CSP ברמה 3.

  • לחצן 'אהבתי' של Facebook כולל מספר אפשרויות הטמעה. מומלץ להישאר בגרסה <iframe>, כי היא מותקנת בבטחה בארגז החול משאר האתר. נדרשת הוראת child-src https://facebook.com כדי לפעול באופן תקין. שימו לב שכברירת מחדל, הקוד <iframe> ש-Facebook מספק טוען כתובת URL יחסית, //facebook.com. משנים את ההגדרה כדי לציין HTTPS באופן מפורש: https://facebook.com. אין סיבה להשתמש ב-HTTP אם אין לכם צורך בכך.

  • לחצן הציוץ של Twitter מסתמך על גישה לסקריפט ולמסגרת, שניהם מתארחים ב-https://platform.twitter.com. (בנוסף, Twitter מספקת כתובת אתר יחסית כברירת מחדל; ערוך את הקוד כדי לציין HTTPS בעת העתקה/הדבקה מקומית). script-src https://platform.twitter.com; child-src https://platform.twitter.com, כל עוד מעבירים את קטע קוד ה-JavaScript ש-Twitter מספק אל קובץ JavaScript חיצוני.

  • לפלטפורמות אחרות יש דרישות דומות, ואפשר לטפל בהן באופן דומה. מומלץ להגדיר default-src של 'none' ולצפות במסוף כדי לקבוע אילו משאבים יפעלו כדי שהווידג'טים יפעלו.

הוספה של מספר ווידג'טים היא פעולה פשוטה: פשוט משלבים את הנחיות המדיניות, ומקפידים למזג את כל המשאבים מאותו סוג להנחיה אחת. אם רציתם את כל שלושת הווידג'טים של המדיה החברתית, המדיניות תיראה כך:

script-src https://apis.google.com https://platform.twitter.com; child-src https://plusone.google.com https://facebook.com https://platform.twitter.com

תרחיש לדוגמה מס' 2: נעילה

נניח לרגע שאתם מפעילים אתר של בנק ואתם רוצים לוודא שניתן לטעון רק את המשאבים שכתבתם בעצמכם. בתרחיש הזה, מתחילים עם מדיניות ברירת מחדל שחוסמת לחלוטין את כל האפשרויות (default-src 'none'), והתחילו משם.

נניח שהבנק טוען את כל התמונות, הסגנונות והסקריפטים מ-CDN ב-https://cdn.mybank.net, ומחבר אותם באמצעות XHR ל-https://api.mybank.com/ כדי לשלוף קטעי נתונים שונים. נעשה שימוש במסגרות, אך רק לדפים מקומיים באתר (ללא מקורות של צד שלישי). בלי Flash באתר, בלי גופנים, בלי תוספות. כותרת ה-CSP המגבילה ביותר שנוכל לשלוח היא:

Content-Security-Policy: default-src 'none'; script-src https://cdn.mybank.net; style-src https://cdn.mybank.net; img-src https://cdn.mybank.net; connect-src https://api.mybank.com; child-src 'self'

תרחיש לדוגמה מס' 3: SSL בלבד

מנהל פורום לטבעות חתונה רוצה לוודא שכל המשאבים נטענים רק דרך ערוצים מאובטחים, אבל לא כותבים הרבה קוד. הוא לא יכול לשכתב חלקים גדולים מתוכנות הפורומים של הצד השלישי, שמלאות במלל ובסגנון מוטבעים. המדיניות הבאה רלוונטית:

Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'

על אף שהמקור https: צוין ב-default-src, הסקריפט והנחיות הסגנון לא יורשים את המקור הזה באופן אוטומטי. כל הוראה מחליפה לחלוטין את ברירת המחדל של סוג המשאב הספציפי.

העתיד

רמה 2 של Content Security Policy היא המלצה למועמדים. בקבוצת העבודה לאבטחת אפליקציות אינטרנט של W3C כבר התחילו לעבוד על איטרציה הבאה של המפרט, רמה 3 של מדיניות אבטחת תוכן (Content Security Policy Level 3).

אם אתם מעוניינים בדיון על התכונות החדשות שיושקו בקרוב, תוכלו לעיין בארכיונים של רשימת התפוצה Public-webappsec@ או להצטרף לעצמכם.

משוב