FixVibe

// docs / baas security / supabase storage

Supabase storage-ბაკეტის უსაფრთხოების სია: 22 პუნქტი

Supabase Storage არის თხელი გადახვევა S3-თავსებად ბაკეტზე პლუს იგივე Row-Level Security მოდელი როგორც მონაცემთა ბაზაში. ეს ნიშნავს, რომ იგივე RLS-ის წინააღმდეგობები, რომლებიც ცხრილებზე მოქმედებენ, ფაილებზე წვდომაზეც მოქმედებენ — და რამდენიმე storage-სპეციფიკური, რომელიც ჩნდება, როცა AI-კოდირების ხელსაწყოები ატვირთვებს უკავშირდებიან. ეს სია არის 22 პუნქტი ხუთ განყოფილებაში: ბაკეტის კონფიგურაცია, RLS-policy-ები, ატვირთვის ვალიდაცია, ხელმოწერილი URL-ები და ოპერაციული ჰიგიენა. თითოეული შესაძლებელია დასამოწმებლად 15 წუთზე ნაკლებში.

ყოველი ქვემოთ მოყვანილი პუნქტი არსებითია. ფონური RLS-მექანიკისთვის, ნახეთ Supabase RLS სკანერი. გასაღების-გამოვლენის კლასისთვის, რომელიც storage-თან არის მიმდებარე, ნახეთ Supabase service role გასაღების გამოვლენა JavaScript-ში.

ბაკეტის კონფიგურაცია

დაიწყეთ სწორი ნაგულისხმევებით. არასწორად კონფიგურირებული ბაკეტი ჟონავს ფაილებს, თქვენი RLS სწორია თუ არა — არ აქვს მნიშვნელობა.

  1. ნაგულისხმევად დააყენეთ ყოველი ბაკეტი პირადად. Supabase Dashboard → Storage → Buckets-ში დააყენეთ Public bucket toggle გათიშულზე, თუ არ გაქვთ ცხადი მიზეზი (მარკეტინგული აქტივები, საჯარო ავატარები PII-ის გარეშე). საჯარო ბაკეტები გვერდს უვლიან RLS-ს წაკითხვის ოპერაციებისთვის — ნებისმიერი ადამიანი, ვისაც ბაკეტის სახელი იცის, შეუძლია ჩამოთვალოს და ჩამოტვირთოს.
  2. დააწესეთ ფაილის ზომის მკაცრი ლიმიტი ყოველ ბაკეტზე. Dashboard → Bucket settings → File size limit. 50 MB არის გონივრული ნაგულისხმევი მომხმარებლის ატვირთვებისთვის; გაზარდეთ მიზანმიმართულად ვიდეო / დიდი-ფაილის გამოყენების შემთხვევებისთვის. ლიმიტის გარეშე, ერთი მავნე ატვირთვა შეიძლება ამოწუროს თქვენი storage-ის კვოტა ან თქვენი ყოველთვიური bandwidth.
  3. შეზღუდეთ დაშვებული MIME-ტიპები ბაკეტზე. დაშვებული MIME-ტიპების სია — ცხადი დაშვების სია, არა ბლოკის სია. image/jpeg, image/png, image/webp მხოლოდ-სურათის ბაკეტებისთვის. არასოდეს დაუშვათ text/html, application/javascript ან image/svg+xml მომხმარებლის-შინაარსის ბაკეტში — ისინი სრულდება ბრაუზერში, როცა ემსახურება ხელმოწერილ URL-ით.
  4. გამოიყენეთ ერთი ბაკეტი ერთ შინაარსის ტიპზე, არა ერთი გაზიარებული ბაკეტი. ბაკეტზე პარამეტრები (ზომა, MIME-ტიპები, RLS-policy-ები) არის ის გრანულობა, რომელიც გაქვთ. user-avatars ბაკეტი, document-uploads ბაკეტი და public-assets ბაკეტი უფრო ადვილია ჩაკეტოს, ვიდრე ერთი შერეული ბაკეტი.
  5. დაამოწმეთ CORS-კონფიგურაცია, თუ frontend ატვირთავს. თუ მომხმარებლები ატვირთავენ პირდაპირ ბრაუზერიდან ხელმოწერილ URL-ზე, ბაკეტის CORS უნდა ჩამოთვალოს თქვენი პროდუქციის origin. * მისაღებია მხოლოდ საჯარო ბაკეტებისთვის — არასოდეს ბაკეტებისთვის, რომლებიც შეიცავენ მომხმარებლის PII-ს.

RLS-policy-ები storage.objects-ზე

Supabase Storage ინახავს ფაილის მეტამონაცემებს storage.objects ცხრილში. RLS ამ ცხრილზე აკონტროლებს, ვის შეუძლია წაიკითხოს, ატვირთოს, განაახლოს ან წაშალოს ფაილები. RLS-ის გარეშე, ბაკეტის საჯარო/პირადი ფლაგი არის თქვენი ერთადერთი დაცვა.

  1. დაადასტურეთ, რომ RLS storage.objects-ზე ჩართულია. SELECT rowsecurity FROM pg_tables WHERE schemaname = 'storage' AND tablename = 'objects'; უნდა დააბრუნოს true. Supabase მას ნაგულისხმევად ჩართავს ახალ პროექტებზე; დაამოწმეთ, რომ ის არ არის გათიშული.
  2. დაწერეთ SELECT-policy, რომელიც 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()-ის გამოყენება მფლობელის გზიდან ამოსაღებად.
  3. დაწერეთ INSERT-policy, რომელიც აღასრულებს იმავე გზის კონვენციას. CREATE POLICY "users_upload_own" ON storage.objects FOR INSERT WITH CHECK (auth.uid()::text = (storage.foldername(name))[1]);. WITH CHECK-ის გარეშე, ავთენტიფიცირებულ მომხმარებელს შეუძლია ატვირთოს სხვა მომხმარებლის საქაღალდეში.
  4. დაამატეთ UPDATE- და DELETE-policy-ები, თუ თქვენი აპი ფაილების რედაქტირებას ან წაშლას უჭერს მხარს. ყოველ ბრძანებას სჭირდება საკუთარი policy. DELETE-ის გამოტოვება ნიშნავს, რომ ავთენტიფიცირებულ მომხმარებლებს არ შეუძლიათ თავიანთი საკუთარი ფაილების წაშლა; UPDATE-ის გამოტოვება ნიშნავს, რომ ფაილის გადაწერა ჩუმად ვერ ხდება.
  5. დაატესტირეთ ჯვარედინი მომხმარებლის წვდომა ორ ბრაუზერის სესიაში. შედით როგორც მომხმარებელი A, ატვირთეთ ფაილი, დააკოპირეთ გზა. შედით როგორც მომხმარებელი B სხვა ბრაუზერში, სცადეთ ფაილის მოპოვება REST API-ით. პასუხი უნდა იყოს 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]);

ატვირთვის ვალიდაცია

დაამოწმეთ ყოველი ატვირთვა სერვერის მხარეს, მაშინაც კი, როცა ბაკეტს აქვს MIME- და ზომის შეზღუდვები. AI-კოდირების ხელსაწყოები ნაგულისხმევად აგენერირებენ მხოლოდ კლიენტის-ვალიდაციას; ეს არაფერს იცავს.

  1. თავიდან შეამოწმეთ MIME-ტიპი სერვერის მხარეს ფაილის რეალური ბაიტებიდან, არა Content-Type header-დან. გამოიყენეთ ბიბლიოთეკა როგორიცაა file-type (Node) ან მაგიური-ბაიტის სუნი. თავდამსხმელს შეუძლია მოახდინოს Content-Type: image/jpeg-ის პრეტენზია ფაილზე, რომელიც სინამდვილეში არის პოლიგლოტი HTML / JavaScript payload.
  2. გაასუფთავეთ EXIF-მეტამონაცემები ატვირთული სურათებიდან. EXIF-ს შეუძლია შეიცავდეს GPS-კოორდინატებს, მოწყობილობის სერიულ ნომრებს და დროის ნიშნებს. გამოიყენეთ sharp .withMetadata(false)-ით ან exif-parser შენახვამდე გაწმენდისთვის.
  3. უარყავით SVG-ები, რომლებიც შეიცავენ script tag-ებს ან onload ჰენდლერებს. SVG არის XML — და ბევრი AI-გენერირებული აპი დაუშვებს SVG-ატვირთვებს, როგორც „უბრალოდ სურათს". გამოიყენეთ DOMPurify სერვერის მხარეს ან მთლიანად უარყავით SVG-ატვირთვები.
  4. გამოიყენეთ დეტერმინისტული, არაგამოცნობადი ფაილების სახელები. ნუ შეინახავთ ორიგინალ ფაილის სახელს. გამოიყენეთ UUID ან ფაილის შინაარსის hash. ორიგინალი ფაილების სახელები ჟონავს ("passport_scan_2024_01_15.jpg") და გასაცნობი სახელები აადვილებენ ჩამოთვლას.

ხელმოწერილი URL-ები

ხელმოწერილი URL-ები არის ის, როგორ წვდებიან კლიენტები პირად ბაკეტებზე. ვადის გასვლა, ბაკეტის სკოპი და რა ლოგდება — მნიშვნელოვანია.

  1. ნაგულისხმევად დააწესეთ ხელმოწერილი-URL-ის ვადის გასვლა 1 საათზე ან ნაკლებზე. Supabase JS SDK-ის createSignedUrl(path, expiresIn) იღებს წამებს. არასოდეს გამოიყენოთ ისეთი მნიშვნელობები, როგორიცაა 31536000 (ერთი წელი) — URL ხდება მუდმივი ნახევრად-საჯარო ლინკი.
  2. არასოდეს შეინახოთ ხელმოწერილი URL-ები თქვენს მონაცემთა ბაზაში. წარმოქმენით ახლები სერვერის მხარეს ყოველ მოთხოვნაზე. შენახული ხელმოწერილი URL 1-წლიანი ვადით, რომელიც ჟონავს მონაცემთა ბაზის dump-ით, აძლევს გრძელვადიან წვდომას.
  3. ლოგი ხელმოწერილი-URL-ის წარმოქმნა, არა მხოლოდ ფაილების ატვირთვები. თუ მოგვიანებით კომპრომისს გეჭვობთ, თქვენ უნდა იცოდეთ, ვინ წარმოქმნა რომელი URL როდის. ლოგი auth.uid() + ბაკეტი + ობიექტის გზა + დროის ნიშანი.
  4. გამოიყენეთ downloadAs ოფცია მომხმარებლის-ატვირთული ფაილების მომსახურებისას. createSignedUrl(path, expiresIn, { download: '.jpg' }) აიძულებს Content-Disposition: attachment header-ს, ისე რომ ფაილი ჩამოიტვირთება ვიდრე გამოისახება — აღმოაჩენს HTML / SVG / HTML-in-PDF შესრულების კლასს.

ოპერაციული ჰიგიენა

Storage-კონფიგურაცია დროთა განმავლობაში დრიფტდება. ეს ოთხი ოპერაციული პუნქტი აკავებს ზედაპირს მჭიდროდ.

  1. ჩაატარეთ ბაკეტების აუდიტი კვარტალურად. Dashboard → Storage → Buckets. დაადასტურეთ, რომ საჯარო/პირადი მდგომარეობა და MIME-ტიპის სიები ემთხვევა იმას, რასაც აპი მოელის. ბაკეტები, რომლებიც „დროებითად" შეიქმნა, მუდმივი ხდება, თუ ვინმე მათ არ ამოიღებს.
  2. აკონტროლეთ ანონიმური list-ოპერაციები. Storage-ლოგები (Dashboard → Logs → Storage) იწერენ LIST-მოთხოვნებს. ანონიმური list-მოთხოვნების ბუნი პირადი ბაკეტის წინააღმდეგ ნიშნავს, რომ ვინმე გარედან ამოწმებს მას.
  3. დააწესეთ შენარჩუნების policy ეფემერული ატვირთვებისთვის. დროებითი ბაკეტები (სურათის ნახვა, draft-ატვირთვები) უნდა ავტო-წაიშალოს 24-72 საათის შემდეგ დანიშნული ფუნქციით. განუსაზღვრელი შენარჩუნება არის ვალდებულება GDPR / CCPA მონაცემთა-მინიმიზაციის ვალდებულებების ფარგლებში.
  4. გაუშვით FixVibe-სკანი ყოველთვიურად. baas.supabase-storage-public შემოწმება ამოწმებს ბაკეტებს, რომლებიც პასუხობენ ანონიმურ GET + LIST-ს. ახალი ბაკეტები ემატება; ძველი ცვლის ხილვადობას — მხოლოდ უწყვეტი სკანირება იჭერს დრიფტს.

შემდეგი ნაბიჯები

გაუშვით FixVibe-სკანი თქვენი პროდუქციის URL-ის წინააღმდეგ — ანონიმური storage-ჩამოთვლები ჩნდება baas.supabase-storage-public-ის ქვეშ. ეს სია დააწყვილეთ Supabase RLS სკანერი-სთან ცხრილის ფენისთვის და Supabase service role გასაღების გამოვლენა JavaScript-ში-სთან გასაღების-გამოვლენის მიმდებარეობისთვის. storage-ის არასწორი კონფიგურაციებისთვის სხვა BaaS-პროვაიდერებთან, ნახეთ BaaS-ის არასწორი კონფიგურაციის სკანერი.

// დაასკანერეთ თქვენი baas-ზედაპირი

იპოვეთ ღია ცხრილი მანამ, სანამ ვინმე სხვა აღმოაჩენს.

შეიყვანეთ პროდუქციის URL. FixVibe აღმოაჩენს BaaS-პროვაიდერებს, რომლებსაც თქვენი აპი ესაუბრება, ამოიცნობს მათ საჯარო endpoint-ებს და გაცნობებთ, რის წაკითხვა ან ჩაწერა შეუძლია არაავთენტიფიცირებულ კლიენტს. უფასოდ, დაყენების გარეშე, ბარათის გარეშე.

  • უფასო ტარიფი — 3 სკანი თვეში, რეგისტრაციის ბარათის გარეშე.
  • პასიური BaaS-fingerprinting — დომენის ვერიფიკაცია არ არის საჭირო.
  • Supabase, Firebase, Clerk, Auth0, Appwrite და სხვები.
  • AI-ფიქს-პრომპტი ყოველი აღმოჩენისთვის — ჩასვით უკან Cursor-ში / Claude Code-ში.
უფასო BaaS-სკანის გაშვება

რეგისტრაცია არ არის საჭირო

Supabase storage-ბაკეტის უსაფრთხოების სია: 22 პუნქტი — Docs · FixVibe