אירוח מאובטח של נתוני משתמשים באפליקציות אינטרנט מודרניות

David Dworken
David Dworken

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

פתרונות קלאסיים לבידוד תוכן לא מהימן

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

  • לעיתים קרובות צריך להגביל את הגישה לתוכן למשתמש יחיד באפליקציות, ולשם כך צריך להטמיע אימות והרשאה. מכיוון שדומיינים של ארגז חול לא משתפים קובצי cookie עם הדומיין הראשי של האפליקציה בכוונה, קשה מאוד לעשות זאת בצורה מאובטחת. כדי לתמוך באימות, אתרים צריכים להסתמך על כתובות URL של יכולות או להגדיר קובצי cookie נפרדים לאימות לדומיין של ארגז החול. השיטה השנייה הזו בעייתית במיוחד באינטרנט המודרני, שבו דפדפנים רבים מגבילים קובצי cookie בכמה אתרים כברירת מחדל.
  • תוכן המשתמש מבודד מהאתר הראשי, אבל לא מתוכן של משתמשים אחרים. כך נוצר סיכון להתקפה על נתונים אחרים בדומיין של ארגז החול על ידי תוכן זדוני של משתמשים (לדוגמה, באמצעות קריאת נתונים מאותו מקור).

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

פתרונות מודרניים להצגת תוכן של משתמשים

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

גישה 1: הצגת תוכן למשתמשים לא פעילים

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

  • תמיד צריך להגדיר את הכותרת Content-Type לסוג MIME ידוע שתומכים בו כל הדפדפנים, ושהוכח שהוא לא מכיל תוכן פעיל (אם אתם לא בטוחים, application/octet-stream היא בחירה בטוחה).
  • בנוסף, תמיד צריך להגדיר את כותרות התגובה הבאות כדי לוודא שהדפדפן מבודד את התגובה באופן מלא.
כותרת התגובה מטרה

X-Content-Type-Options: nosniff

מניעת ניטור תוכן

Content-Disposition: attachment; filename="download"

מפעילה הורדה במקום רינדור

Content-Security-Policy: sandbox

המערכת מעבירה את התוכן לארגז חול כאילו הוא הוצג בדומיין נפרד

Content-Security-Policy: default-src ‘none'

השבתת ההרצה של JavaScript (והכללה של משאבי משנה)

Cross-Origin-Resource-Policy: same-site

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

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

הגנה לעומק

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

  • מגדירים כותרת X-Content-Security-Policy: sandbox לצורך תאימות ל-IE11.
  • מגדירים כותרת Content-Security-Policy: frame-ancestors 'none' כדי לחסום את הטמעת נקודת הקצה.
  • תוכן של משתמשי Sandbox בתת-דומיין מבודד:
    • הצגת תוכן של משתמשים בתת-דומיין מבודד (למשל, Google משתמשת בדומיינים כמו product.usercontent.google.com).
    • מגדירים את Cross-Origin-Opener-Policy: same-origin ו-Cross-Origin-Embedder-Policy: require-corp כדי להפעיל בידוד בין מקורות.

גישה 2: הצגת תוכן למשתמשים פעילים

אפשר גם להציג תוכן פעיל (למשל, תמונות HTML או SVG) בצורה בטוחה, בלי נקודות החולשה של הגישה הקלאסית לדומיין ב-sandbox.
האפשרות הפשוטה ביותר היא להשתמש בכותרת Content-Security-Policy: sandbox כדי להורות לדפדפן לבודד את התגובה. נכון לעכשיו, לא כל הדפדפנים מטמיעים בידוד תהליכים למסמכים בארגז חול, אבל סביר להניח ששיפורים מתמשכים במודלים של תהליכי הדפדפן ישפרו את ההפרדה בין תוכן בארגז חול לבין אפליקציות מוטמעות. אם ההתקפות של SpectreJS והפרת אבטחה של ה-renderer לא נכללות במודל האיומים שלכם, סביר להניח ששימוש ב-sandbox של CSP יספק פתרון מספיק.
ב-Google פיתחנו פתרון שיכול לבודד באופן מלא תוכן פעיל לא מהימן על ידי עדכון הקונספט של דומיינים ב-sandbox. הרעיון המרכזי הוא:

  • יוצרים דומיין חדש בארגז החול שנוסף לרשימת הסיומות הציבוריות. לדוגמה, הוספת exampleusercontent.com ל-PSL מאפשרת לוודא ש-foo.exampleusercontent.com ו-bar.exampleusercontent.com פועלים באתרים שונים, ולכן הם מבודדים זה מזה לחלוטין.
  • כל כתובות ה-URL שתואמות ל-*.exampleusercontent.com/shim מנותבות לקובץ shim סטטי. קובץ ה-shim הזה מכיל קטע HTML קצר ו-JavaScript שמאזין למטפל האירועים message ומעבד כל תוכן שהוא מקבל.
  • כדי לעשות זאת, המוצר יוצר iframe או חלון קופץ ל-$RANDOM_VALUE.exampleusercontent.com/shim ומשתמש ב-postMessage כדי לשלוח את התוכן הלא מהימן ל-shim לצורך עיבוד.
  • התוכן שעבר עיבוד הופך ל-Blob ומעובד בתוך iframe בארגז חול.

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

סיכום

שני הפתרונות האלה מאפשרים לעבור מדומיינים קלאסיים של ארגז חול, כמו googleusercontent.com, לפתרונות מאובטחים יותר שתואמים לחסימת קובצי cookie של צד שלישי. ב-Google, כבר העברנו מוצרים רבים לשימוש בפתרונות האלה, ואנחנו מתכננים להעביר עוד מוצרים בשנה הבאה.