1. ספרייה
  2. HTTP והרשת
  3. כותרות HTTP

עודכן לפני חודש

כותרות אבטחה קיימות מפני שאינך סומך על הקוד שלך — ובצדק.

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

זוהי התובנה האמיתית: כותרות אבטחה הן מעקות בטיחות שאתה מתקין מפני שאתה יודע שאתה טועה לפעמים.

Strict-Transport-Security (HSTS)

HTTPS חסר משמעות אם תוקף יכול לרמות את הדפדפן להשתמש ב-HTTP במקום. HSTS הופך את HTTPS לחובה.

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

ברגע שהדפדפן רואה כותרת זו, הוא מסרב להתחבר דרך HTTP. כל בקשה הופכת אוטומטית ל-HTTPS. אם האישור לא תקין, אין כפתור עקיפה — הדפדפן פשוט לא יתחבר.

ההנחיות

max-age קובע כמה זמן הדפדפן זוכר את הכלל הזה. 31,536,000 שניות הן שנה אחת.

includeSubDomains מרחיב את הכלל לכל תת-הדומיינים. ודא שכל תת-דומיין תומך ב-HTTPS לפני שתפעיל זאת — תשבור את אלה שלא תומכים.

preload מאפשר לך להגיש את הדומיין שלך לרשימות ה-preload של הדפדפן בכתובת hstspreload.org. אלה הם דומיינים המקודדים ישירות לתוך הדפדפנים כ-HTTPS בלבד.

בעיית הביקור הראשון

ל-HSTS יש מגבלה כנה: הוא אינו יכול להגן על הביקור הראשון. לפני שהדפדפן מקבל את הכותרת, הוא אינו יודע להשתמש ב-HTTPS. תוקף שמיירט את החיבור הראשון יכול לשדרג אותו לאחור ל-HTTP.

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

Content-Security-Policy (CSP)

CSP היא כותרת האבטחה החזקה ביותר. היא אומרת לדפדפן בדיוק אילו משאבים מותר לטעון ולהריץ.

Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'

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

ההנחיות המרכזיות

default-src הוא ערך ברירת המחדל עבור כל סוג משאב שלא הגדרת במפורש:

default-src 'self'

script-src שולט מהיכן ניתן לטעון JavaScript:

script-src 'self' https://trusted.cdn.com

style-src שולט בגיליונות סגנון:

style-src 'self' 'unsafe-inline'

img-src שולט בתמונות:

img-src 'self' data: https:

connect-src שולט ב-fetch, XMLHttpRequest, WebSocket, ו-EventSource:

connect-src 'self' https://api.example.com

frame-ancestors שולט במי שיכול להטמיע את הדף שלך במסגרת:

frame-ancestors 'none'

ערכי מקור

'none' חוסם הכל:

script-src 'none'

'self' מאפשר את המקור שלך בלבד:

script-src 'self'

'unsafe-inline' מאפשר סקריפטים מוטבעים — הימנע מכך אם אפשר:

script-src 'unsafe-inline'

'unsafe-eval' מאפשר eval() — הימנע מכך גם כן:

script-src 'unsafe-eval'

nonce-[value] מאפשר סקריפטים מוטבעים ספציפיים הכוללים nonce תואם:

script-src 'nonce-rAnd0m123'
<script nonce="rAnd0m123">
  // הסקריפט רץ מפני שה-nonce תואם
</script>

מקורות דומיין מאפשרים מקורות ספציפיים:

script-src https://trusted.cdn.com

התחלה עם מדיניות מחמירה

התחל עם מדיניות מגבילה:

default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self'; connect-src 'self'

לאחר מכן הרפה רק את מה שנשבר. השתמש במצב Report-Only כדי לבדוק ללא חסימה:

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

זה רושם הפרות מבלי לאכוף, כדי שתוכל לזהות מה המדיניות שלך תשבור לפני שתפרוס אותה.

X-Content-Type-Options

דפדפנים לפעמים מתעלמים ממה שאמרת להם שקובץ הוא, ומנחשים במקום. תמונה עשויה להתפרש כ-JavaScript. קובץ טקסט עשוי להתרנדר כ-HTML.

X-Content-Type-Options: nosniff

הנחיה יחידה זו אומרת לדפדפן: סמוך על כותרת ה-Content-Type. אל תנחש. אם משהו מוגדר כתמונה, התייחס אליו כתמונה — אל תריץ אותו כקוד.

X-Frame-Options

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

X-Frame-Options: DENY

DENY מונע כל הטמעה במסגרת. SAMEORIGIN מאפשר הטמעה רק על ידי המקור שלך עצמו.

אפליקציות מודרניות צריכות להשתמש ב-frame-ancestors של CSP במקום:

Content-Security-Policy: frame-ancestors 'none'

CSP מספקת גמישות רבה יותר, ו-X-Frame-Options הוא בעצם מיושן.

Referrer-Policy

כאשר אתה לוחץ על קישור, הדפדפן שלך מספר ליעד מאיפה הגעת. כתובת ה-URL של ה-referrer עשויה להכיל מידע רגיש — טוקנים, מזהי סשן, נתונים אישיים במחרוזות שאילתה.

Referrer-Policy: strict-origin-when-cross-origin

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

אפשרויות נוספות:

  • no-referrer: לעולם אל תשלח מידע referrer
  • same-origin: שלח referrer רק עבור בקשות מאותו מקור
  • strict-origin: שלח רק את המקור, ולא כלום בעת שדרוג לאחור ל-HTTP

Permissions-Policy

אם האתר שלך לא משתמש במצלמה, מדוע שאיזשהו סקריפט בדף שלך יוכל לגשת אליה?

Permissions-Policy: geolocation=(), microphone=(), camera=()

הסוגריים הריקים משמעותם שאף מקור אינו מורשה. גם אם תוקף מזריק קוד זדוני, הוא לא יוכל לגשת לממשקי API אלה.

כדי לאפשר תכונות ספציפיות למקור שלך:

Permissions-Policy: geolocation=(self), payment=(self "https://trusted-payment.com")

כותרות בידוד חוצות-מקור

שלוש כותרות פועלות יחד כדי לבודד את הדף שלך מהתערבות חוצת-מקור:

Cross-Origin-Embedder-Policy (COEP):

Cross-Origin-Embedder-Policy: require-corp

משאבים חייבים לבחור במפורש להיטען על ידי הדף שלך.

Cross-Origin-Opener-Policy (COOP):

Cross-Origin-Opener-Policy: same-origin

מבודד את הקשר הגלישה שלך מדפים חוצי-מקור.

Cross-Origin-Resource-Policy (CORP):

Cross-Origin-Resource-Policy: same-origin

שולט באילו מקורות יכולים לטעון את המשאבים שלך.

כותרות אלה מאפשרות תכונות עוצמתיות כמו SharedArrayBuffer תוך הגנה מפני התקפות בסגנון Spectre.

יישום

Nginx:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Apache:

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set Content-Security-Policy "default-src 'self'"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Header always set Referrer-Policy "strict-origin-when-cross-origin"

Node.js עם Helmet:

const helmet = require('helmet');
app.use(helmet());

Helmet קובע ברירות מחדל סבירות לכל כותרות האבטחה המרכזיות.

בדיקת הכותרות שלך

השתמש ב-securityheaders.com או ב-Mozilla Observatory לביקורת התצורה שלך. לחלופין, בדוק ידנית ב-DevTools של הדפדפן: פתח את לשונית ה-Network, לחץ על כל בקשה, ובחן את כותרות התגובה.

התחל עם HSTS ו-CSP — הם מספקים את ההגנה הרבה ביותר. הוסף את האחרים בהדרגה. השתמש במצב Report-Only עבור CSP עד שתהיה בטוח במדיניות שלך.

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

שאלות נפוצות על כותרות אבטחה

האם כותרות אבטחה מחליפות שיטות קידוד מאובטחות?

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

מה הסט המינימלי של כותרות אבטחה שכדאי ליישם?

התחל עם ארבע אלה: Strict-Transport-Security (כופה HTTPS), Content-Security-Policy (מונעת XSS), X-Content-Type-Options: nosniff (מונעת בלבול MIME), ו-X-Frame-Options: DENY או CSP frame-ancestors (מונעת clickjacking). אלה מכסות את וקטורי התקיפה הנפוצים ביותר.

מדוע CSP כל כך קשה לביצוע נכון?

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

האם עדיין כדאי להגדיר X-XSS-Protection?

דפדפנים מודרניים הוציאו אותו מכלל שימוש לטובת CSP. חלק ממומחי האבטחה ממליצים להשבית אותו במפורש עם X-XSS-Protection: 0 כדי למנוע עקיפות במקרי קצה בדפדפנים ישנים. התרכז במקום בזה ב-CSP חזקה.

האם דף זה היה מועיל?

😔
🤨
😃