גם אתר סטטי לגמרי צריך כותרות אבטחה — חמש שורות שסוגרות דלתות
רגע של רקע למי שלא מכיר: אתר סטטי הוא אתר שכל העמודים שלו מוכנים מראש כקבצים — אין שרת שמריץ קוד או ניגש למסד נתונים כשגולש נכנס. כותרות HTTP (headers) הן שורות מידע קטנות שהשרת מצרף לכל תשובה שהוא שולח לדפדפן — מין פתק הוראות שאומר לדפדפן איך להתנהג עם מה שקיבל.
עכשיו לאינטואיציה הנפוצה: "האתר שלי סטטי, אין מה לפרוץ". הבעיה — חלק מהתקיפות לא צריכות שרת חלש בכלל. הן משתמשות בדפדפן של הגולש נגדו:
Clickjacking ("חטיפת קליקים") — אתר זדוני מטמיע את האתר שלך בתוך iframe (חלון-בתוך-חלון) שקוף, ומפתה גולשים ללחוץ "על" כפתורים שלך בלי שהם יודעים. ההגנה היא שורה אחת שאוסרת להטמיע את האתר: X-Frame-Options: DENY.
MIME sniffing — דפדפנים אוהבים "לנחש" סוג של קובץ לפי התוכן שלו, וניחוש כזה יכול לגרום לקובץ תמים לרוץ כקוד. X-Content-Type-Options: nosniff מכבה את הניחושים.
שדרוג לאחור ל-HTTP — הכותרת Strict-Transport-Security אומרת לדפדפן: מהביקור הראשון והלאה, דבר איתי רק בחיבור מוצפן (HTTPS), לשנתיים קדימה.
הסט המלא שהגדרתי:
const securityHeaders = [
{ key: "Content-Security-Policy", value: csp },
{ key: "Strict-Transport-Security",
value: "max-age=63072000; includeSubDomains; preload" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "X-Frame-Options", value: "DENY" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{ key: "Permissions-Policy",
value: "camera=(), microphone=(), geolocation=()" },
];
ובונוס: poweredByHeader: false — למה לספר לסורקים אוטומטיים באיזו טכנולוגיה ובאיזו גרסה האתר רץ?
מאחורי כל השורות האלה עומד רעיון אחד שנקרא עקרון ההרשאה המינימלית (Principle of Least Privilege): כל יכולת שלא חייבים — חוסמים במפורש. האתר לא צריך מצלמה? חסומה. לא אמור להיות מוטמע באתרים אחרים? אסור. עולה חמש שורות, וסוגר קטגוריות שלמות של תקיפות.