// 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 სწორია თუ არა — არ აქვს მნიშვნელობა.
- ნაგულისხმევად დააყენეთ ყოველი ბაკეტი პირადად. Supabase Dashboard → Storage → Buckets-ში დააყენეთ Public bucket toggle გათიშულზე, თუ არ გაქვთ ცხადი მიზეზი (მარკეტინგული აქტივები, საჯარო ავატარები PII-ის გარეშე). საჯარო ბაკეტები გვერდს უვლიან RLS-ს წაკითხვის ოპერაციებისთვის — ნებისმიერი ადამიანი, ვისაც ბაკეტის სახელი იცის, შეუძლია ჩამოთვალოს და ჩამოტვირთოს.
- დააწესეთ ფაილის ზომის მკაცრი ლიმიტი ყოველ ბაკეტზე. Dashboard → Bucket settings → File size limit. 50 MB არის გონივრული ნაგულისხმევი მომხმარებლის ატვირთვებისთვის; გაზარდეთ მიზანმიმართულად ვიდეო / დიდი-ფაილის გამოყენების შემთხვევებისთვის. ლიმიტის გარეშე, ერთი მავნე ატვირთვა შეიძლება ამოწუროს თქვენი storage-ის კვოტა ან თქვენი ყოველთვიური bandwidth.
- შეზღუდეთ დაშვებული MIME-ტიპები ბაკეტზე. დაშვებული MIME-ტიპების სია — ცხადი დაშვების სია, არა ბლოკის სია.
image/jpeg,image/png,image/webpმხოლოდ-სურათის ბაკეტებისთვის. არასოდეს დაუშვათtext/html,application/javascriptანimage/svg+xmlმომხმარებლის-შინაარსის ბაკეტში — ისინი სრულდება ბრაუზერში, როცა ემსახურება ხელმოწერილ URL-ით. - გამოიყენეთ ერთი ბაკეტი ერთ შინაარსის ტიპზე, არა ერთი გაზიარებული ბაკეტი. ბაკეტზე პარამეტრები (ზომა, MIME-ტიპები, RLS-policy-ები) არის ის გრანულობა, რომელიც გაქვთ.
user-avatarsბაკეტი,document-uploadsბაკეტი დაpublic-assetsბაკეტი უფრო ადვილია ჩაკეტოს, ვიდრე ერთი შერეული ბაკეტი. - დაამოწმეთ CORS-კონფიგურაცია, თუ frontend ატვირთავს. თუ მომხმარებლები ატვირთავენ პირდაპირ ბრაუზერიდან ხელმოწერილ URL-ზე, ბაკეტის CORS უნდა ჩამოთვალოს თქვენი პროდუქციის origin.
*მისაღებია მხოლოდ საჯარო ბაკეტებისთვის — არასოდეს ბაკეტებისთვის, რომლებიც შეიცავენ მომხმარებლის PII-ს.
RLS-policy-ები 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-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()-ის გამოყენება მფლობელის გზიდან ამოსაღებად. - დაწერეთ INSERT-policy, რომელიც აღასრულებს იმავე გზის კონვენციას.
CREATE POLICY "users_upload_own" ON storage.objects FOR INSERT WITH CHECK (auth.uid()::text = (storage.foldername(name))[1]);. WITH CHECK-ის გარეშე, ავთენტიფიცირებულ მომხმარებელს შეუძლია ატვირთოს სხვა მომხმარებლის საქაღალდეში. - დაამატეთ UPDATE- და DELETE-policy-ები, თუ თქვენი აპი ფაილების რედაქტირებას ან წაშლას უჭერს მხარს. ყოველ ბრძანებას სჭირდება საკუთარი policy. 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- და ზომის შეზღუდვები. AI-კოდირების ხელსაწყოები ნაგულისხმევად აგენერირებენ მხოლოდ კლიენტის-ვალიდაციას; ეს არაფერს იცავს.
- თავიდან შეამოწმეთ MIME-ტიპი სერვერის მხარეს ფაილის რეალური ბაიტებიდან, არა
Content-Typeheader-დან. გამოიყენეთ ბიბლიოთეკა როგორიცააfile-type(Node) ან მაგიური-ბაიტის სუნი. თავდამსხმელს შეუძლია მოახდინოსContent-Type: image/jpeg-ის პრეტენზია ფაილზე, რომელიც სინამდვილეში არის პოლიგლოტი HTML / JavaScript payload. - გაასუფთავეთ EXIF-მეტამონაცემები ატვირთული სურათებიდან. EXIF-ს შეუძლია შეიცავდეს GPS-კოორდინატებს, მოწყობილობის სერიულ ნომრებს და დროის ნიშნებს. გამოიყენეთ
sharp.withMetadata(false)-ით ანexif-parserშენახვამდე გაწმენდისთვის. - უარყავით SVG-ები, რომლებიც შეიცავენ
scripttag-ებს ანonloadჰენდლერებს. SVG არის XML — და ბევრი AI-გენერირებული აპი დაუშვებს SVG-ატვირთვებს, როგორც „უბრალოდ სურათს". გამოიყენეთDOMPurifyსერვერის მხარეს ან მთლიანად უარყავით SVG-ატვირთვები. - გამოიყენეთ დეტერმინისტული, არაგამოცნობადი ფაილების სახელები. ნუ შეინახავთ ორიგინალ ფაილის სახელს. გამოიყენეთ UUID ან ფაილის შინაარსის hash. ორიგინალი ფაილების სახელები ჟონავს ("
passport_scan_2024_01_15.jpg") და გასაცნობი სახელები აადვილებენ ჩამოთვლას.
ხელმოწერილი URL-ები
ხელმოწერილი URL-ები არის ის, როგორ წვდებიან კლიენტები პირად ბაკეტებზე. ვადის გასვლა, ბაკეტის სკოპი და რა ლოგდება — მნიშვნელოვანია.
- ნაგულისხმევად დააწესეთ ხელმოწერილი-URL-ის ვადის გასვლა 1 საათზე ან ნაკლებზე. Supabase JS SDK-ის
createSignedUrl(path, expiresIn)იღებს წამებს. არასოდეს გამოიყენოთ ისეთი მნიშვნელობები, როგორიცაა31536000(ერთი წელი) — URL ხდება მუდმივი ნახევრად-საჯარო ლინკი. - არასოდეს შეინახოთ ხელმოწერილი URL-ები თქვენს მონაცემთა ბაზაში. წარმოქმენით ახლები სერვერის მხარეს ყოველ მოთხოვნაზე. შენახული ხელმოწერილი URL 1-წლიანი ვადით, რომელიც ჟონავს მონაცემთა ბაზის dump-ით, აძლევს გრძელვადიან წვდომას.
- ლოგი ხელმოწერილი-URL-ის წარმოქმნა, არა მხოლოდ ფაილების ატვირთვები. თუ მოგვიანებით კომპრომისს გეჭვობთ, თქვენ უნდა იცოდეთ, ვინ წარმოქმნა რომელი URL როდის. ლოგი
auth.uid()+ ბაკეტი + ობიექტის გზა + დროის ნიშანი. - გამოიყენეთ
downloadAsოფცია მომხმარებლის-ატვირთული ფაილების მომსახურებისას.createSignedUrl(path, expiresIn, { download: '.jpg' })აიძულებსContent-Disposition: attachmentheader-ს, ისე რომ ფაილი ჩამოიტვირთება ვიდრე გამოისახება — აღმოაჩენს HTML / SVG / HTML-in-PDF შესრულების კლასს.
ოპერაციული ჰიგიენა
Storage-კონფიგურაცია დროთა განმავლობაში დრიფტდება. ეს ოთხი ოპერაციული პუნქტი აკავებს ზედაპირს მჭიდროდ.
- ჩაატარეთ ბაკეტების აუდიტი კვარტალურად. Dashboard → Storage → Buckets. დაადასტურეთ, რომ საჯარო/პირადი მდგომარეობა და MIME-ტიპის სიები ემთხვევა იმას, რასაც აპი მოელის. ბაკეტები, რომლებიც „დროებითად" შეიქმნა, მუდმივი ხდება, თუ ვინმე მათ არ ამოიღებს.
- აკონტროლეთ ანონიმური list-ოპერაციები. Storage-ლოგები (Dashboard → Logs → Storage) იწერენ
LIST-მოთხოვნებს. ანონიმური list-მოთხოვნების ბუნი პირადი ბაკეტის წინააღმდეგ ნიშნავს, რომ ვინმე გარედან ამოწმებს მას. - დააწესეთ შენარჩუნების policy ეფემერული ატვირთვებისთვის. დროებითი ბაკეტები (სურათის ნახვა, draft-ატვირთვები) უნდა ავტო-წაიშალოს 24-72 საათის შემდეგ დანიშნული ფუნქციით. განუსაზღვრელი შენარჩუნება არის ვალდებულება GDPR / CCPA მონაცემთა-მინიმიზაციის ვალდებულებების ფარგლებში.
- გაუშვით FixVibe-სკანი ყოველთვიურად.
baas.supabase-storage-publicშემოწმება ამოწმებს ბაკეტებს, რომლებიც პასუხობენ ანონიმურGET+LIST-ს. ახალი ბაკეტები ემატება; ძველი ცვლის ხილვადობას — მხოლოდ უწყვეტი სკანირება იჭერს დრიფტს.
შემდეგი ნაბიჯები
გაუშვით FixVibe-სკანი თქვენი პროდუქციის URL-ის წინააღმდეგ — ანონიმური storage-ჩამოთვლები ჩნდება baas.supabase-storage-public-ის ქვეშ. ეს სია დააწყვილეთ Supabase RLS სკანერი-სთან ცხრილის ფენისთვის და Supabase service role გასაღების გამოვლენა JavaScript-ში-სთან გასაღების-გამოვლენის მიმდებარეობისთვის. storage-ის არასწორი კონფიგურაციებისთვის სხვა BaaS-პროვაიდერებთან, ნახეთ BaaS-ის არასწორი კონფიგურაციის სკანერი.
