// docs / baas security / supabase service role exposure
Supabase service role გასაღების გამოვლენა JavaScript-ში: რას ნიშნავს და როგორ ვიპოვოთ
Supabase service role გასაღები არის თქვენი მონაცემთა ბაზის უფროსი გასაღები. ნებისმიერი, ვინც მას ფლობს, გვერდს უვლის Row-Level Security-ს, შეუძლია წაიკითხოს ყოველი ცხრილის ყოველი სვეტი და შეუძლია ჩაწეროს ან წაშალოს ნებისმიერი, რასაც აირჩევს. ის გათვლილია იცხოვროს მხოლოდ სერვერის მხარის კოდში — არასოდეს ბრაუზერში. როცა AI-კოდირების ხელსაწყო მას აგზავნის JavaScript-ბანდლში, თქვენი მონაცემთა ბაზა, ფაქტობრივად, საჯაროა. ეს სტატია ხსნის JWT-ფორმას, რომელიც გამოვლენილ გასაღებს ამოიცნობს, სამ AI-ხელსაწყოს შაბლონს, რომელიც წარმოშობს გამოვლენას, რა გავაკეთოთ პირველ საათში გამოვლენის შემდეგ და როგორ დავასკანეროთ ის ავტომატურად მომხმარებლებზე ადრე.
რა არის service role გასაღები
Supabase გასცემს ორ განსხვავებულ გასაღებს ყოველი პროექტისთვის: anon-გასაღებს (ასევე ეწოდება გამოსაქვეყნებელი გასაღები ახალ პროექტებში) და service_role-გასაღებს. ორივე არის JSON Web Token, ხელმოწერილი თქვენი პროექტის JWT-საიდუმლოთი. განსხვავება არის role claim-ი, რომელიც ჩახედულია JWT-payload-ში — anon საჯარო გასაღებისთვის, service_role უფროსი გასაღებისთვის. PostgREST, Supabase Storage და Supabase Auth ყველა გადადის ყველაფრის გვერდს ავლის რეჟიმში, როცა ისინი ხედავენ service_role claim-ს.
გაშიფრეთ ნებისმიერი Supabase-გასაღები jwt.io-ზე და დააკვირდით payload-ს. service-role JWT-ის ფორმა შეუცდომელია:
service-role JWT-ის გაშიფრული payload (ნაჩვენებია როგორც სინტაქს-მონიშნული ბლოკი ქვემოთ).
{
"iss": "supabase",
"ref": "[project-ref]",
"role": "service_role",
"iat": 1700000000,
"exp": 2000000000
}ახალი Supabase-პროექტები გასცემენ secret-სტილის გასაღებებს sb_secret_ პრეფიქსით JWT-ის ნაცვლად. ქცევა იდენტურია — ნებისმიერი, რომელიც ატარებს sb_secret_-ს საჯარო ბანდლში, თანაბრად კატასტროფულია.
როგორ ჟონავენ AI-კოდირების ხელსაწყოები service role გასაღებს
ჩვენ ვნახეთ ერთი და იგივე სამი შაბლონი ათასობით vibe-coded აპებში. თითოეული იწყება დეველოპერით, რომელიც AI-ხელსაწყოს ეხმარება სთხოვს და მთავრდება service-key-ის ბანდლში მიწებებით.
შაბლონი 1: ერთი .env ფაილი NEXT_PUBLIC_ პრეფიქსით
დეველოპერი სთხოვს AI-ხელსაწყოს „დააყენე Supabase" და იღებს ერთ .env-ს ორივე გასაღებით. AI-ხელსაწყო — გაწვრთნილი კორპუსზე, სადაც გარემოს ცვლადების უმეტესობა გამოვლენილია NEXT_PUBLIC_*-ით — ორივეს NEXT_PUBLIC_-ით აპრეფიქსებს. Next.js ჩასვამს ნებისმიერს, რომელიც ემთხვევა ამ პრეფიქსს კლიენტის ბანდლში build-time-ზე. Vercel-ზე გაგზავნისას service-key არის main.[hash].js-ში.
შაბლონი 2: არასწორი გასაღები createClient გამოძახებაში
დეველოპერი ჩასვამს ორივე გასაღებს config.ts ფაილში, რომელიც AI-მ შექმნა და AI ცდომილებით ავსებს ბრაუზერის მხარის createClient() გამოძახებას process.env.SUPABASE_SERVICE_ROLE_KEY-ით. Build-ი ცვლადს იძენს და JWT ბანდლში ხვდება.
შაბლონი 3: service-role გასაღები ჩაკოდილია seed-სკრიპტებში
დეველოპერი სთხოვს AI-ხელსაწყოს დაწეროს სკრიპტი, რომელიც მონაცემთა ბაზას აყრიდრის. AI ჩაკოდავს service-role გასაღებს პირდაპირ ფაილში (გარემოდან წაკითხვის ნაცვლად), commit-ს უკეთებს ფაილს რეპოზიტორიაში და საჯარო GitHub-რეპო ან დეპლოიდი აპის /scripts/seed.js route ახლა გასცემს გასაღებს.
როგორ აღმოაჩენს FixVibe-ის ბანდლ-სკანი გამოვლენას
FixVibe-ის ბანდლ-საიდუმლოების შემოწმება ჩამოტვირთავს ყოველ JavaScript-ფაილს, რომელიც დეპლოიდი აპის მიერ არის მითითებული — entry chunks, lazy-loaded chunks, web workers, service workers — და ატარებს მათ დეტექტორში, რომელიც გაშიფრავს ნებისმიერს, რომელიც JWT-ფორმას ემთხვევა (eyJ[base64-header].eyJ[base64-payload].[signature]). თუ გაშიფრული payload შეიცავს "role": "service_role", სკანი მოახსენებს მას როგორც კრიტიკულ აღმოჩენას ფაილის გზასთან და ზუსტ ხაზთან ერთად, სადაც გასაღები ჩნდება. იგივე შემოწმება ასევე ემთხვევა უფრო ახალ sb_secret_* შაბლონს პრეფიქსით.
სკანი არასოდეს ავთენტიფიცირდება აღმოჩენილი გასაღებით. ის ამოიცნობს ფორმას და მოახსენებს გამოვლენას — გასაღების გამოყენება ექსპლუატაციის დასადასტურებლად იქნებოდა თქვენი მონაცემთა ბაზის უუფლებო წვდომა. დასაბუთება არის თვითონ JWT-payload-ში.
აღმოჩენილია — რა გავაკეთოთ პირველ საათში
გამოვლენილი service role გასაღები არის საგანგებო რეჟიმის სიტუაცია. ჩათვალეთ, რომ გასაღები გადათრეულია — თავდამსხმელები რეალურ დროში თვალს ადევნებენ საჯარო ბანდლებს. მიეპყარით მონაცემთა ბაზას, როგორც კომპრომეტირებულს, სანამ არ შეცვლით გასაღებს და არ ჩაატარებთ ბოლო აქტივობის აუდიტს.
- დაუყოვნებლივ შეცვალეთ გასაღები. Supabase Dashboard-ში გადადით Project Settings → API → Service role key → Reset-ში. ძველი გასაღები აუქმდება წამებში. ნებისმიერი სერვერის მხარის კოდი, რომელიც გასაღებს იყენებს, უნდა განახლდეს და თავიდან გაიშვას, სანამ ცვლა მოხდება.
- ჩაატარეთ ბოლო მონაცემთა ბაზის აქტივობის აუდიტი. გახსენით Database → Logs dashboard-ში. ფილტრი ბოლო 7 დღეზე. ეძებეთ უჩვეულო
SELECT *მოთხოვნებს PII-ის შემცველი ცხრილების წინააღმდეგ, დიდUPDATE- ანDELETE-დებულებებს და მოთხოვნებს IP-დან თქვენი ცნობილი ინფრასტრუქტურის გარეთ. Supabase ლოგავსx-real-ipheader-ს ყოველ მოთხოვნაზე. - შეამოწმეთ storage ობიექტები. ეწვიეთ Storage → Logs-ს და განიხილეთ ბოლო ფაილების ჩამოტვირთვები. გამოვლენილი service-role გასაღები იძლევა ყველაფრის გვერდს ავლის წვდომას პირად ბაკეტებზეც.
- ამოიღეთ გასაღები წყაროს კონტროლიდან. ცვლის შემდეგაც კი, JWT-ის დატოვება თქვენი git-ის ისტორიაში ნიშნავს, რომ ის აღმოჩენადია საჯარო რეპოში. გამოიყენეთ
git filter-repoან BFG Repo-Cleaner მისი ისტორიიდან გასაწმენდად, შემდეგ force-push (გააფრთხილეთ თანამშრომლები წინასწარ). - თავიდან დაასკანერეთ გასწორების შემდეგ. გაუშვით ახალი FixVibe-სკანი თავიდან დეპლოიდი აპის წინააღმდეგ. ბანდლ-საიდუმლოების აღმოჩენა უნდა გაიწმინდოს. დარწმუნდით, რომ არც ერთი
service_roleJWT და არც ერთიsb_secret_*სტრიქონი არ რჩება არც ერთ chunk-ში.
გამოვლენის თავიდან აცილება
სტრუქტურული გასწორება არის სახელდების დისციპლინა პლუს ხელსაწყოს დონის დამცავი მექანიზმები:
- არასოდეს მიამატოთ service-key-ს
NEXT_PUBLIC_*,VITE_*ან რომელიმე სხვა ბანდლ-ჩამშენებელი პრეფიქსი. სახელდების კონვენცია არის საზღვარი — ყოველი ფრეიმვორქი მას პატივს სცემს. - დატოვეთ service-key მთლიანად დეველოპერის მანქანის
.env-ის გარეთ. წაიკითხეთ ის საიდუმლოს მენეჯერიდან (Doppler, Infisical, Vercel-ის დაშიფრული env-ცვლადები) დეპლოიზე, არასოდეს commit გაუკეთოთ ლოკალურად. - <strong>Mark every Supabase client construction with explicit context.</strong> Files named <code>supabase/browser.ts</code> use the anon key; files named <code>supabase/server.ts</code> use the service-role key with <code>import 'server-only'</code> at the top. The <code>server-only</code> import causes a build error if a client component tries to consume the module.
- <strong>Add a pre-commit hook that greps for JWT-shaped strings.</strong> <code>git diff --staged | grep -E 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+'</code> catches both anon and service tokens before they leave your machine.
- დაამატეთ CI-კარიბჭე, რომელიც სკანერავს build-ის ოუტფუთს.
next build-ის შემდეგ grep-ით ეძებეთ.next/static/chunks/ოუტფუთშიservice_roleსტრიქონს. დააფეილეთ build-ი, თუ რაიმე ემთხვევა.
# Pre-commit hook: refuse any staged JWT-shaped string.
git diff --staged \
| grep -E 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+' \
&& echo "JWT detected in staged changes — refusing commit" \
&& exit 1
# CI gate: fail the build if "service_role" shipped to the static bundle.
grep -RE 'service_role|sb_secret_' .next/static/chunks/ \
&& echo "Service-role credential leaked into bundle" \
&& exit 1ხშირად დასმული შეკითხვები
რა სიჩქარით პოულობენ თავდამსხმელები გამოვლენილ Supabase service-role გასაღებებს?
საჯარო-ბანდლის სკანერები გადადგამენ ახალ დეპლოიმენტებს წუთებში. მკვლევრებმა დააფიქსირეს მუშა ექსპლოიტები ახალი Supabase-პროექტების წინააღმდეგ პირველი დეპლოის შემდეგ ერთ საათში. მიეპყარით ნებისმიერ service-role გამოვლენას, როგორც 60-წუთიან ფანჯარას, არა 60-დღიანს.
გასაღების ცვლა საკმარისია, თუ ვალდებული ვარ ვივარაუდო მონაცემების ექსფილტრაცია?
ცვლა აუქმებს გამოვლენილ გასაღებს, მაგრამ უკან ვერ აბრუნებს უკვე გადათრეულ მონაცემებს. თუ თქვენი ცხრილები შეიცავენ PII-ს, გადახდის მონაცემებს ან ნებისმიერ რეგულირებად მონაცემებს, შესაძლოა გქონდეთ შეტყობინების ვალდებულება GDPR-ის (72 საათი), CCPA-ის ან HIPAA-ის ფარგლებში. ჩაატარეთ ლოგების აუდიტი და გაიარეთ კონსულტაცია იურისტთან, თუ აუდიტი საეჭვო წვდომას აჩვენებს.
RLS-ს შეუძლია დამიცვას, თუ service-role გასაღები გამოვლინდა?
არა. Row-Level Security სრულად გვერდს უვლის service_role claim-ით. ეს არის გათვლილი — გასაღები არსებობს ზუსტად იმისთვის, რომ ბექენდის კოდი RLS-ს გვერდს უვლის ადმინ-ოპერაციებისთვის. შემარბილებელი ფაქტორი არის იმის უზრუნველყოფა, რომ გასაღები არასოდეს არ მიაღწევს კონტექსტს, სადაც თავდამსხმელს მისი წაკითხვა შეუძლია.
ეს ეხება ახალ Supabase publishable / secret გასაღების მოდელს (<code>sb_publishable_</code> / <code>sb_secret_</code>)?
კი — იდენტური რისკის კლასი. sb_secret_* გასაღები არის ახალი secret-გასაღების ფორმატი, რომელიც ცვლის service-role JWT-ს ახალი პროექტებისთვის. ნებისმიერი რამ, რომელიც ატარებს sb_secret_*-ს ბანდლში, ისეთივე კატასტროფულია, როგორც გამოვლენილი service-role JWT. FixVibe-ის ბანდლ-საიდუმლოების დეტექტორი ემთხვევა ორივე ფორმას.
რა შეიძლება ითქვას anon / publishable გასაღებზე — ის უსაფრთხოა ბანდლში?
კი, გათვლის მიხედვით. anon-გასაღები გათვლილია იცხოვროს ბრაუზერში და ის არის ის, რასაც ყოველი Supabase-ვებ-კლიენტი იყენებს. მისი უსაფრთხოება მთლიანად დამოკიდებულია იმაზე, RLS სწორად არის თუ არა კონფიგურირებული ყოველ საჯარო ცხრილზე. ნახეთ Supabase RLS სკანერი სტატია, თუ რა შესამოწმებელია.
შემდეგი ნაბიჯები
გაუშვით FixVibe-სკანი თქვენი პროდუქციის URL-ის წინააღმდეგ — ბანდლ-საიდუმლოების შემოწმება უფასოა, რეგისტრაციის გარეშე და მოახსენებს service_role-ის გამოვლენას წუთზე ნაკლებში. ეს დაუწყვილეთ Supabase RLS სკანერი სტატიას, რათა დაამოწმოთ, რომ RLS-ის ფენა თავის საქმეს აკეთებს, და Supabase storage-ბაკეტის უსაფრთხოების სია-ს, რათა ჩაკეტოთ ფაილებზე წვდომა. ფონური ცოდნისთვის, რატომ წარმოშობენ AI-ხელსაწყოები ამ გამოვლენის კლასს ასე საიმედოდ, წაიკითხეთ რატომ ტოვებენ AI-კოდირების ხელსაწყოები უსაფრთხოების ხარვეზებს.
