// docs / baas security / supabase storage
רשימת בדיקה לאבטחת דליי אחסון של Supabase: 22 פריטים
Supabase Storage הוא עטיפה דקה סביב דלי תואם-S3 פלוס אותו מודל Row-Level Security של מסד הנתונים. זה אומר שאותן מלכודות RLS שמשפיעות על טבלאות משפיעות על גישה לקבצים — ועוד כמה ספציפיות לאחסון שמופיעות כשכלי קוד מבוססי-AI מחברים העלאות. הרשימה הזו היא 22 פריטים על פני חמישה חלקים: תצורת דלי, מדיניויות RLS, אימות העלאה, URLs חתומים, והיגיינה תפעולית. כל אחד ניתן לאימות תוך פחות מ-15 דקות.
כל פריט להלן הוא חיוני. עבור מכניקות ה-RLS הבסיסיות, ראה סורק Supabase RLS. עבור מחלקת חשיפת המפתח הסמוכה לאחסון, ראה מפתח Supabase service role חשוף ב-JavaScript.
תצורת דלי
התחל עם ברירות המחדל הנכונות. דלי מוגדר שגוי דולף קבצים בין אם ה-RLS שלך נכון ובין אם לא.
- הגדר כל דלי כברירת מחדל לפרטי. ב-Dashboard של Supabase → Storage → Buckets, הגדר את מתג Public bucket ל-off אלא אם יש לך סיבה מפורשת (נכסי שיווק, אווטרים ציבוריים ללא PII). דליים ציבוריים עוקפים RLS עבור פעולות קריאה — כל מי שיודע את שם הדלי יכול לרשום ולהוריד.
- הגדר מגבלת גודל קובץ קשיחה על כל דלי. Dashboard → הגדרות דלי → מגבלת גודל קובץ. 50 MB הוא ברירת מחדל הגיונית להעלאות משתמש; העלה אותה במכוון עבור מקרי שימוש של וידאו / קבצים גדולים. ללא מגבלה, העלאה זדונית אחת יכולה למצות את מכסת האחסון שלך או את רוחב הפס החודשי שלך.
- הגבל סוגי MIME מותרים לכל דלי. רשימת סוגי MIME מותרים — רשימת היתר מפורשת, לא רשימת חסימה.
image/jpeg,image/png,image/webpלדליים של תמונות בלבד. לעולם אל תתירtext/html,application/javascript, אוimage/svg+xmlבדלי תוכן משתמש — הם מורצים בדפדפן כשהם משרתים דרך URL חתום. - השתמש בדלי אחד לכל סוג תוכן, לא בדלי משותף אחד. הגדרות לכל דלי (גודל, סוגי MIME, מדיניויות RLS) הן הגרגריות שיש לך. דלי
user-avatars, דליdocument-uploads, ודליpublic-assetsקלים יותר לנעילה מדלי מעורב אחד. - אמת תצורת CORS אם העלאות מצד הלקוח. אם משתמשים מעלים ישירות מהדפדפן ל-URL חתום, ה-CORS של הדלי חייב לרשום את מקור הייצור שלך.
*מקובל רק לדליים ציבוריים — לעולם לא לדליים המכילים PII של משתמשים.
מדיניויות RLS על storage.objects
Supabase Storage מאחסן מטא-נתוני קבצים בטבלת storage.objects. RLS על אותה טבלה שולט במי יכול לקרוא, להעלות, לעדכן או למחוק קבצים. ללא RLS, דגל הציבורי/פרטי של הדלי הוא ההגנה היחידה שלך.
- אשר ש-RLS מופעל על storage.objects.
SELECT rowsecurity FROM pg_tables WHERE schemaname = 'storage' AND tablename = 'objects';חייב להחזירtrue. Supabase מפעיל זאת כברירת מחדל בפרויקטים חדשים; אמת שלא הושבת. - כתוב מדיניות SELECT מצומצמת ל-
auth.uid()עבור דליים פרטיים.CREATE POLICY "users_read_own_files" ON storage.objects FOR SELECT USING (auth.uid()::text = (storage.foldername(name))[1]);. המוסכמה היא לאחסן קבצים תחת[user-id]/[filename]ולהשתמש ב-storage.foldername()כדי לחלץ את הבעלים מהנתיב. - כתוב מדיניות INSERT שאוכפת את אותה מוסכמת נתיב.
CREATE POLICY "users_upload_own" ON storage.objects FOR INSERT WITH CHECK (auth.uid()::text = (storage.foldername(name))[1]);. ללא WITH CHECK, משתמש מאומת יכול להעלות לתיקייה של משתמש אחר. - הוסף מדיניויות UPDATE ו-DELETE אם האפליקציה שלך תומכת בעריכת או מחיקת קבצים. כל פקודה צריכה את המדיניות שלה. דילוג על DELETE אומר שמשתמשים מאומתים לא יכולים להסיר את הקבצים שלהם; דילוג על UPDATE אומר שדריסת קבצים נכשלת בשקט.
- בדוק גישה בין-משתמשים בשני session דפדפן. היכנס כמשתמש A, העלה קובץ, העתק את הנתיב. היכנס כמשתמש B בדפדפן אחר, נסה למשוך את הקובץ דרך ה-REST API. התגובה חייבת להיות
403או404, לעולם לא200.
-- Confirm RLS on storage.objects
SELECT rowsecurity
FROM pg_tables
WHERE schemaname = 'storage' AND tablename = 'objects';
-- SELECT policy: scope reads to the owning user's folder.
CREATE POLICY "users_read_own_files"
ON storage.objects
FOR SELECT
USING (auth.uid()::text = (storage.foldername(name))[1]);
-- INSERT policy: enforce the [user-id]/[filename] path convention.
CREATE POLICY "users_upload_own"
ON storage.objects
FOR INSERT
WITH CHECK (auth.uid()::text = (storage.foldername(name))[1]);אימות העלאה
אמת כל העלאה בצד-שרת, אפילו כשלדלי יש אילוצי MIME וגודל. כלי קוד מבוססי-AI מייצרים אימות של צד-לקוח בלבד כברירת מחדל; זה לא מגן על כלום.
- בדוק מחדש סוג MIME בצד-שרת מהבייטים בפועל של הקובץ, לא מ-header ה-
Content-Type. השתמש בספרייה כמוfile-type(Node) או רחרוח byte קסום. תוקף יכול לטעוןContent-Type: image/jpegעל קובץ שהוא בעצם payload פוליגלוט של HTML / JavaScript. - הסר מטא-נתוני EXIF מתמונות מועלות. EXIF יכול להכיל קואורדינטות GPS, מספרים סידוריים של מכשירים, וחותמות זמן. השתמש ב-
sharpעם.withMetadata(false)אוexif-parserכדי להסיר לפני האחסון. - דחה SVGs שמכילים תגי
scriptאו handlers שלonload. SVG הוא XML — והרבה אפליקציות שנוצרו על-ידי AI מתירות העלאות SVG כ"סתם תמונה". השתמש ב-DOMPurifyבצד-שרת או סרב להעלאות SVG לחלוטין. - השתמש בשמות קבצים דטרמיניסטיים ובלתי-ניתנים-לניחוש. אל תשמר את שם הקובץ המקורי. השתמש ב-UUID או hash של תוכן הקובץ. שמות קבצים מקוריים מדליפים ("
passport_scan_2024_01_15.jpg") ושמות צפויים מאפשרים מנייה.
URLs חתומים
URLs חתומים הם איך שלקוחות ניגשים לדליים פרטיים. תוקף הפקיעה, היקף הדלי, ומה שמתועד חשובים.
- הגדר תוקף URL חתום כברירת מחדל לשעה או פחות.
createSignedUrl(path, expiresIn)של JS SDK של Supabase לוקח שניות. לעולם אל תשתמש בערכים כמו31536000(שנה אחת) — ה-URL הופך לקישור חצי-ציבורי קבוע. - לעולם אל תאחסן URLs חתומים במסד הנתונים שלך. צור חדשים בצד-שרת בכל בקשה. URL חתום מאוחסן עם תוקף של שנה שדולף דרך dump של מסד נתונים מעניק גישה ארוכת-טווח.
- תעד יצירת URL חתום, לא רק העלאות קבצים. אם אתה חושד בפריצה מאוחר יותר, אתה צריך לדעת מי יצר איזה URL ומתי. תעד
auth.uid()+ דלי + נתיב אובייקט + חותמת זמן. - השתמש באפשרות
downloadAsכשמשרתים קבצים מועלים-על-ידי-משתמש.createSignedUrl(path, expiresIn, { download: '.jpg' })אוכף headerContent-Disposition: attachmentכך שהקובץ מורד במקום להיות מוצג — מובס את מחלקת הביצוע של HTML / SVG / HTML-בתוך-PDF.
היגיינה תפעולית
תצורת אחסון נסחפת עם הזמן. ארבעת הפריטים התפעוליים האלה שומרים את המשטח הדוק.
- בצע audit לדליים רבעוני. Dashboard → Storage → Buckets. אשר שמצב ציבורי/פרטי ורשימות סוגי MIME תואמים למה שהאפליקציה מצפה. דליים שנוצרו "זמנית" הופכים לקבועים אם אף אחד לא מסיר אותם.
- נטר פעולות רישום אנונימיות. יומני אחסון (Dashboard → Logs → Storage) רושמים בקשות
LIST. עלייה חדה בבקשות רישום אנונימיות מול דלי פרטי אומרת שמישהו בוחן אותו מבחוץ. - הגדר מדיניות שמירה להעלאות זמניות. דליי טמפ (תצוגה מקדימה של תמונה, העלאות טיוטה) צריכים להימחק אוטומטית אחרי 24-72 שעות דרך פונקציה מתוזמנת. שמירה ללא הגבלת זמן היא התחייבות תחת חובות מינימיזציית-נתונים של GDPR / CCPA.
- הרץ סריקת FixVibe חודשית. בדיקת
baas.supabase-storage-publicבוחנת אחר דליים שמגיבים ל-GET+LISTאנונימיים. דליים חדשים נוספים; ישנים משנים נראות — רק סריקה רציפה לוכדת את הסחיפה.
צעדים הבאים
הרץ סריקת FixVibe מול URL הייצור שלך — רישומי אחסון אנונימיים מופיעים תחת baas.supabase-storage-public. צמד את הרשימה הזו עם סורק Supabase RLS עבור שכבת הטבלה ו-מפתח Supabase service role חשוף ב-JavaScript עבור הסמיכות של חשיפת מפתחות. עבור תצורות שגויות של אחסון בספקי BaaS אחרים, ראה סורק תצורות שגויות של BaaS.
