FixVibe

// docs / baas security / supabase storage

Supabase storage bucket checklist ความปลอดภัย: 22 ข้อ

Supabase Storage เป็น wrapper บาง ๆ รอบ bucket ที่เข้ากันได้กับ S3 บวกกับโมเดล Row-Level Security เหมือนกับฐานข้อมูล นั่นหมายความว่าข้อผิดพลาด RLS แบบเดียวกันที่ส่งผลกระทบต่อตารางก็ส่งผลกระทบต่อการเข้าถึงไฟล์ — และยังมีข้อผิดพลาดเฉพาะ storage อีกไม่กี่ข้อที่ปรากฏเมื่อเครื่องมือ AI Coding เชื่อมต่อการอัปโหลด checklist นี้คือ 22 ข้อใน 5 ส่วน: การตั้งค่า bucket, RLS policy, การตรวจสอบการอัปโหลด, signed URL และ operational hygiene แต่ละข้อตรวจสอบได้ในเวลาไม่ถึง 15 นาที

ทุกข้อด้านล่างมีความสำคัญ สำหรับกลไก RLS ที่อยู่เบื้องหลัง โปรดดู Supabase RLS scanner สำหรับ class การเปิดเผย key ที่อยู่ใกล้ storage โปรดดู Supabase service role key ถูกเปิดเผยใน JavaScript

การตั้งค่า bucket

เริ่มต้นด้วยค่าเริ่มต้นที่ถูกต้อง bucket ที่ตั้งค่าผิดทำให้ไฟล์รั่วไหลไม่ว่า RLS ของคุณจะถูกต้องหรือไม่

  1. ตั้งค่า bucket ทุกตัวเป็น private โดยค่าเริ่มต้น ใน Supabase Dashboard → Storage → Buckets ตั้งค่า toggle Public bucket เป็นปิดเว้นแต่คุณจะมีเหตุผลที่ชัดเจน (asset การตลาด, avatar สาธารณะที่ไม่มี PII) Public bucket ข้าม RLS สำหรับการอ่าน — ใครก็ตามที่มีชื่อ bucket สามารถ list และดาวน์โหลดได้
  2. ตั้งค่าจำกัดขนาดไฟล์เด็ดขาดในทุก bucket Dashboard → Bucket settings → File size limit 50 MB เป็นค่าเริ่มต้นที่สมเหตุสมผลสำหรับการอัปโหลดของผู้ใช้; เพิ่มอย่างจงใจสำหรับวิดีโอ / กรณีใช้งานไฟล์ขนาดใหญ่ หากไม่มีการจำกัด การอัปโหลดที่เป็นอันตรายเพียงครั้งเดียวสามารถทำให้พื้นที่ storage หรือ bandwidth รายเดือนของคุณหมด
  3. จำกัด MIME type ที่อนุญาตต่อ bucket รายการ MIME types ที่อนุญาต — allowlist ที่ชัดเจน ไม่ใช่ blocklist image/jpeg, image/png, image/webp สำหรับ bucket ที่เก็บเฉพาะรูปภาพ ห้ามอนุญาต text/html, application/javascript หรือ image/svg+xml ใน bucket เนื้อหาของผู้ใช้ — พวกมัน execute ในเบราว์เซอร์เมื่อเสิร์ฟผ่าน signed URL
  4. ใช้ bucket หนึ่งต่อประเภทเนื้อหาหนึ่ง ไม่ใช่ bucket ร่วมเดียว การตั้งค่าต่อ bucket (ขนาด, MIME type, RLS policy) คือระดับความละเอียดที่คุณมี bucket ของ user-avatars, bucket ของ document-uploads และ bucket ของ public-assets ล็อกได้ง่ายกว่า bucket ผสมเดียว
  5. ตรวจสอบการตั้งค่า CORS หากอัปโหลดจาก frontend ถ้าผู้ใช้อัปโหลดจากเบราว์เซอร์โดยตรงไปที่ signed URL CORS ของ bucket ต้องระบุ origin production ของคุณ * ยอมรับได้สำหรับ public bucket เท่านั้น — ห้ามใช้กับ bucket ที่มี PII ของผู้ใช้

RLS policy บน storage.objects

Supabase Storage เก็บ metadata ของไฟล์ในตาราง storage.objects RLS บนตารางนั้นควบคุมว่าใครสามารถอ่าน, อัปโหลด, อัปเดต หรือลบไฟล์ได้ หากไม่มี RLS ธง public/private ของ bucket คือการป้องกันเพียงอย่างเดียวของคุณ

  1. ยืนยันว่า RLS เปิดอยู่บน storage.objects SELECT rowsecurity FROM pg_tables WHERE schemaname = 'storage' AND tablename = 'objects'; ต้องคืน true Supabase เปิดมันเป็นค่าเริ่มต้นบนโปรเจกต์ใหม่; ตรวจสอบว่ามันไม่ได้ถูกปิด
  2. เขียน SELECT policy ที่จำกัดด้วย auth.uid() สำหรับ private bucket CREATE POLICY "users_read_own_files" ON storage.objects FOR SELECT USING (auth.uid()::text = (storage.foldername(name))[1]); ตามแบบแผน เก็บไฟล์ใต้ [user-id]/[filename] และใช้ storage.foldername() เพื่อดึงเจ้าของจาก path
  3. เขียน INSERT policy ที่บังคับแบบแผน path เดียวกัน CREATE POLICY "users_upload_own" ON storage.objects FOR INSERT WITH CHECK (auth.uid()::text = (storage.foldername(name))[1]); หากไม่มี WITH CHECK ผู้ใช้ที่ผ่านการ authenticate สามารถอัปโหลดเข้าไปในโฟลเดอร์ของผู้ใช้อื่นได้
  4. เพิ่ม UPDATE และ DELETE policy หากแอปของคุณรองรับการแก้ไขหรือลบไฟล์ แต่ละคำสั่งต้องมี policy ของตัวเอง การข้าม DELETE หมายความว่าผู้ใช้ที่ผ่านการ authenticate ไม่สามารถลบไฟล์ของตัวเองได้; การข้าม UPDATE หมายความว่าการเขียนทับไฟล์ล้มเหลวอย่างเงียบ ๆ
  5. ทดสอบการเข้าถึงข้ามผู้ใช้ใน session เบราว์เซอร์สอง session เข้าสู่ระบบในฐานะ User A, อัปโหลดไฟล์, copy path เข้าสู่ระบบในฐานะ User B ในเบราว์เซอร์อื่น พยายามดึงไฟล์ผ่าน REST API response ต้องเป็น 403 หรือ 404, ไม่เคยเป็น 200
sql
-- 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]);

การตรวจสอบการอัปโหลด

ตรวจสอบการอัปโหลดทุกครั้งฝั่งเซิร์ฟเวอร์ แม้ว่า bucket จะมีข้อจำกัด MIME และขนาด เครื่องมือ AI Coding สร้างการตรวจสอบเฉพาะฝั่ง client โดยค่าเริ่มต้น; นั่นไม่ปกป้องอะไรเลย

  1. ตรวจสอบ MIME type ใหม่ฝั่งเซิร์ฟเวอร์จากไบต์จริงของไฟล์ ไม่ใช่จาก header Content-Type ใช้ library อย่าง file-type (Node) หรือ magic-byte sniffing ผู้โจมตีสามารถอ้าง Content-Type: image/jpeg บนไฟล์ที่จริงๆ แล้วเป็น polyglot HTML / JavaScript payload
  2. ลบ EXIF metadata จากภาพที่อัปโหลด EXIF สามารถมีพิกัด GPS, หมายเลข serial ของอุปกรณ์ และ timestamp ใช้ sharp พร้อม .withMetadata(false) หรือ exif-parser เพื่อลบก่อนการจัดเก็บ
  3. ปฏิเสธ SVG ที่มี script tag หรือ onload handler SVG เป็น XML — และแอปที่สร้างจาก AI หลายตัวอนุญาตการอัปโหลด SVG ในฐานะ "ก็แค่รูปภาพ" ใช้ DOMPurify ฝั่งเซิร์ฟเวอร์หรือปฏิเสธการอัปโหลด SVG ทั้งหมด
  4. ใช้ชื่อไฟล์ที่กำหนดได้และคาดเดาไม่ได้ อย่าเก็บชื่อไฟล์ดั้งเดิม ใช้ UUID หรือ hash ของเนื้อหาไฟล์ ชื่อไฟล์ดั้งเดิมรั่วไหล ("passport_scan_2024_01_15.jpg") และชื่อที่คาดเดาได้ทำให้ enumerate ได้

Signed URL

Signed URL คือวิธีที่ client เข้าถึง private bucket ระยะเวลาหมดอายุ, ขอบเขต bucket และสิ่งที่ log ล้วนสำคัญ

  1. ตั้งค่าระยะเวลาหมดอายุ signed-URL เริ่มต้นเป็น 1 ชั่วโมงหรือน้อยกว่า Supabase JS SDK createSignedUrl(path, expiresIn) รับเป็นวินาที ห้ามใช้ค่าเช่น 31536000 (หนึ่งปี) — URL กลายเป็นลิงก์กึ่งสาธารณะถาวร
  2. ห้ามเก็บ signed URL ในฐานข้อมูล สร้างใหม่ฝั่งเซิร์ฟเวอร์ในทุก request signed URL ที่เก็บไว้ซึ่งมีอายุ 1 ปีและรั่วไหลผ่าน database dump จะให้สิทธิ์การเข้าถึงระยะยาว
  3. Log การสร้าง signed URL ไม่ใช่แค่การอัปโหลดไฟล์ หากคุณสงสัยว่ามีการบุกรุกในภายหลัง คุณต้องรู้ว่าใครสร้าง URL ไหนเมื่อไหร่ Log auth.uid() + bucket + object path + timestamp
  4. ใช้ option downloadAs เมื่อเสิร์ฟไฟล์ที่ผู้ใช้อัปโหลด createSignedUrl(path, expiresIn, { download: '.jpg' }) บังคับ header Content-Disposition: attachment ดังนั้นไฟล์ดาวน์โหลดแทนที่จะ render — ปิด class การ execute HTML / SVG / HTML-in-PDF

Operational hygiene

การตั้งค่า storage เลื่อนไหลตามกาลเวลา สี่ข้อนี้ทำให้พื้นผิวคงความตึง

  1. Audit bucket ทุกไตรมาส Dashboard → Storage → Buckets ยืนยันสถานะ public/private และรายการ MIME-type ตรงกับที่แอปคาดหวัง bucket ที่สร้าง "ชั่วคราว" กลายเป็นถาวรหากไม่มีใครลบ
  2. ตรวจสอบการดำเนินการ list แบบ anonymous Storage log (Dashboard → Logs → Storage) บันทึก request LIST การเพิ่มขึ้นของ anonymous list request กับ private bucket หมายความว่ามีคนกำลังตรวจสอบจากภายนอก
  3. ตั้งนโยบายการเก็บรักษาสำหรับการอัปโหลดชั่วคราว Temp bucket (image preview, draft upload) ควรลบอัตโนมัติหลังจาก 24-72 ชั่วโมงผ่านฟังก์ชันที่กำหนดเวลา การเก็บรักษาแบบไม่จำกัดเป็นภาระภายใต้ภาระผูกพันการลดข้อมูลของ GDPR / CCPA
  4. รัน FixVibe scan รายเดือน check baas.supabase-storage-public ตรวจสอบ bucket ที่ตอบสนองต่อ anonymous GET + LIST bucket ใหม่ถูกเพิ่ม; bucket เก่าเปลี่ยน visibility — เฉพาะการสแกนต่อเนื่องเท่านั้นที่จับการเลื่อนไหลได้

ขั้นตอนถัดไป

รัน FixVibe scan กับ URL production ของคุณ — รายการ storage แบบ anonymous ปรากฏใต้ baas.supabase-storage-public จับคู่ checklist นี้กับ Supabase RLS scanner สำหรับชั้นตารางและ Supabase service role key ถูกเปิดเผยใน JavaScript สำหรับ adjacency การเปิดเผย key สำหรับการตั้งค่า storage ผิดข้าม BaaS provider อื่นๆ โปรดดู BaaS misconfiguration scanner

// สแกนพื้นผิว baas ของคุณ

ค้นหาตารางที่เปิดอยู่ก่อนที่คนอื่นจะพบ

ใส่ URL production ของคุณ FixVibe จะระบุผู้ให้บริการ BaaS ที่แอปของคุณติดต่อด้วย, ทำ fingerprint endpoint สาธารณะของพวกเขา และรายงานสิ่งที่ client ที่ไม่ได้ผ่านการ authenticate สามารถอ่านหรือเขียนได้ ฟรี ไม่ต้องติดตั้ง ไม่ต้องใช้บัตร

  • ระดับฟรี — 3 scans ต่อเดือน ไม่ต้องใช้บัตรในการสมัคร
  • การทำ fingerprint BaaS แบบ passive — ไม่ต้องยืนยันโดเมน
  • Supabase, Firebase, Clerk, Auth0, Appwrite และอื่นๆ
  • AI fix prompt ในทุก finding — วางกลับเข้าไปใน Cursor / Claude Code
เริ่มสแกน BaaS ฟรี

ไม่ต้องสมัครสมาชิก

Supabase storage bucket checklist ความปลอดภัย: 22 ข้อ — Docs · FixVibe