// docs / baas security / supabase storage
قائمة التحقق لأمان دلاء Supabase Storage: 22 بندًا
Supabase Storage عبارة عن غلاف رفيع حول دلو متوافق مع S3 بالإضافة إلى نفس نموذج Row-Level Security مثل قاعدة البيانات. هذا يعني أن نفس مشاكل RLS التي تؤثر على الجداول تؤثر على الوصول إلى الملفات — وبضع مشاكل خاصة بالتخزين تظهر عندما تربط أدوات البرمجة بالذكاء الاصطناعي عمليات الرفع. هذه القائمة من 22 بندًا عبر خمسة أقسام: تكوين الدلو، وسياسات RLS، والتحقق من الرفع، وعناوين URL الموقَّعة، والنظافة التشغيلية. كل واحد قابل للتحقق في أقل من 15 دقيقة.
كل بند أدناه أساسي. للأساسيات التقنية لـ RLS، راجع ماسح Supabase RLS. لفئة كشف المفاتيح المجاورة للتخزين، راجع مفتاح Supabase service role المكشوف في JavaScript.
تكوين الدلو
ابدأ بالافتراضيات الصحيحة. يُسرِّب الدلو المُهيأ بشكل خاطئ الملفات سواء كان RLS الخاص بك صحيحًا أم لا.
- اجعل كل دلو افتراضيًا خاصًا. في لوحة Supabase → Storage → Buckets، اضبط مفتاح Public bucket على إيقاف ما لم يكن لديك سبب صريح (أصول تسويقية، صور رمزية عامة دون معلومات شخصية). تتجاوز الدلاء العامة RLS لعمليات القراءة — يمكن لأي شخص يعرف اسم الدلو سرد الملفات وتنزيلها.
- اضبط حدًا صلبًا لحجم الملف على كل دلو. لوحة → إعدادات الدلو → حد حجم الملف. 50 ميغابايت افتراضيًا منطقي لعمليات رفع المستخدمين؛ ارفعه عمدًا لحالات الاستخدام الخاصة بالفيديو / الملفات الكبيرة. بدون حد، يمكن لرفع خبيث واحد استنفاد حصة التخزين أو عرض النطاق الترددي الشهري.
- قيِّد أنواع 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 الخاص بالدلو أصل الإنتاج الخاص بك.
*مقبول للدلاء العامة فقط — أبدًا للدلاء التي تحتوي على معلومات شخصية للمستخدم.
سياسات 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 يعني أن إعادة كتابة الملفات تفشل بصمت.
- اختبر الوصول عبر المستخدمين في جلستي متصفح. سجِّل الدخول كالمستخدم 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 والحجم. تُولِّد أدوات البرمجة بالذكاء الاصطناعي التحقق من جانب العميل فقط افتراضيًا؛ هذا لا يحمي شيئًا.
- أعد فحص نوع MIME على الخادم من بايتات الملف الفعلية، لا من ترويسة
Content-Type. استخدم مكتبة مثلfile-type(Node) أو شم البايتات السحرية. يمكن لمهاجم ادعاءContent-Type: image/jpegعلى ملف هو في الواقع حمولة polyglot HTML / JavaScript. - جرِّد بيانات EXIF من الصور المرفوعة. يمكن أن يحتوي EXIF على إحداثيات GPS، وأرقام تسلسلية للأجهزة، وطوابع زمنية. استخدم
sharpمع.withMetadata(false)أوexif-parserللتجريد قبل التخزين. - ارفض ملفات SVG التي تحتوي على وسوم
scriptأو معالجاتonload. SVG هو XML — والعديد من التطبيقات المُولَّدة بالذكاء الاصطناعي تسمح برفع SVG كـ "مجرد صورة". استخدمDOMPurifyعلى الخادم أو ارفض رفع SVG تمامًا. - استخدم أسماء ملفات حتمية لا يمكن تخمينها. لا تحتفظ بالاسم الأصلي. استخدم UUID أو هاش لمحتويات الملف. الأسماء الأصلية تُسرِّب ("
passport_scan_2024_01_15.jpg") والأسماء التي يمكن التنبؤ بها تُمكِّن التعداد.
عناوين URL الموقَّعة
عناوين URL الموقَّعة هي كيف يصل العملاء إلى الدلاء الخاصة. تاريخ انتهاء الصلاحية، ونطاق الدلو، وما يُسجَّل، كلها مهمة.
- اجعل افتراضي انتهاء صلاحية URL الموقَّع ساعة واحدة أو أقل. دالة
createSignedUrl(path, expiresIn)في Supabase JS SDK تأخذ ثوانٍ. لا تستخدم أبدًا قيمًا مثل31536000(سنة واحدة) — يصبح URL رابطًا دائمًا شبه عام. - لا تخزِّن أبدًا عناوين URL الموقَّعة في قاعدة بياناتك. ولِّد عناوين جديدة على الخادم مع كل طلب. URL موقَّع مخزَّن بانتهاء صلاحية سنة واحدة يتسرب عبر تفريغ قاعدة بيانات يمنح وصولًا طويل الأمد.
- سجِّل توليد URL الموقَّع، لا فقط رفع الملفات. إذا اشتبهت في اختراق لاحقًا، فأنت بحاجة لمعرفة من ولَّد أي URL ومتى. سجِّل
auth.uid()+ الدلو + مسار الكائن + الطابع الزمني. - استخدم خيار
downloadAsعند تقديم الملفات المرفوعة من المستخدم.createSignedUrl(path, expiresIn, { download: '.jpg' })يُجبر ترويسةContent-Disposition: attachmentلتنزيل الملف بدلًا من عرضه — يهزم فئة تنفيذ HTML / SVG / HTML في PDF.
النظافة التشغيلية
تكوين التخزين ينحرف بمرور الوقت. هذه العناصر التشغيلية الأربعة تحافظ على السطح ضيقًا.
- راجع الدلاء فصليًا. لوحة → Storage → Buckets. تأكد من أن الحالة عام/خاص وقوائم أنواع MIME تتطابق مع ما يتوقعه التطبيق. الدلاء التي تُنشأ "مؤقتًا" تصبح دائمة إذا لم يُزلها أحد.
- راقب عمليات السرد المجهولة. سجلات التخزين (لوحة → 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.
