// docs / baas security / supabase service role exposure
Сервизният ключ на Supabase, разкрит в JavaScript: какво означава и как да го намерите
Сервизният ключ на Supabase е главният ключ за вашата база данни. Всеки, който го притежава, заобикаля Row-Level Security, може да чете всяка колона от всяка таблица и може да пише или изтрива каквото си поиска. Той е проектиран да живее изключително в сървърен код — никога в браузъра. Когато AI инструмент за кодиране го изпрати в JavaScript bundle-а, базата ви данни на практика е публична. Тази статия обяснява формата на JWT, която идентифицира изтекъл ключ, трите модела на AI инструменти, които произвеждат изтичането, какво да правите в първия час след откриване и как да сканирате за него автоматично, преди потребителите да го направят.
Какво представлява сервизният ключ
Supabase издава два различни ключа за всеки проект: anon ключ (наричан също публикуем ключ в по-нови проекти) и service_role ключ. И двата са JSON Web Token-и, подписани с JWT секрета на проекта ви. Разликата е claim-ът role, вграден в payload-а на JWT — anon за публичния ключ, service_role за главния ключ. PostgREST, Supabase Storage и Supabase Auth превключват в режим на пълно заобикаляне, когато видят claim service_role.
Декодирайте всеки Supabase ключ на jwt.io и погледнете payload-а. Формата на service-role JWT е неподражаема:
Декодиран payload на service-role JWT (показан като syntax-highlighted блок по-долу).
{
"iss": "supabase",
"ref": "[project-ref]",
"role": "service_role",
"iat": 1700000000,
"exp": 2000000000
}По-новите Supabase проекти издават ключове в стил secret с префикс sb_secret_ вместо JWT. Поведението е идентично — всичко, носещо sb_secret_ в публичен bundle, е също толкова катастрофално.
Как AI инструментите за кодиране изтичат сервизния ключ
Видяли сме същите три модела в хиляди vibe-кодирани приложения. Всеки започва с разработчик, който моли AI инструмент за помощ, и завършва със сервизния ключ, вграден в bundle.
Модел 1: Единичен .env файл с префикс NEXT_PUBLIC_
Разработчикът моли AI инструмента да "настрои Supabase" и приема единичен .env с двата ключа. AI инструментът — обучен върху корпус, в който повечето променливи на средата са изложени чрез NEXT_PUBLIC_* — поставя префикс NEXT_PUBLIC_ и на двата. Next.js вгражда всичко, съответстващо на този префикс, в клиентския bundle по време на build. Изпратете към Vercel и сервизният ключ е в main.[hash].js.
Модел 2: Грешен ключ в извикването на createClient
Разработчикът поставя двата ключа във файл config.ts, генериран от AI, и AI попълва извикването на createClient() на страната на браузъра с process.env.SUPABASE_SERVICE_ROLE_KEY по грешка. Build-ът внася променливата и JWT попада в bundle-а.
Модел 3: Service-role ключ, hardcoded в seed скриптове
Разработчикът моли AI инструмента да напише скрипт, който инициализира базата данни. AI hardcode-ва service-role ключа директно във файла (вместо да чете от средата), commit-ва файла в repo-то и публичното GitHub repo или маршрутът /scripts/seed.js на внедреното приложение вече сервира ключа.
Как сканирането на bundle на FixVibe открива изтичането
Проверката bundle-secrets на 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.
Открито — какво да направите в първия час
Изтекъл сервизен ключ е runtime спешен случай. Приемете, че ключът е изкопиран — нападателите наблюдават публични bundle-и в реално време. Третирайте базата данни като компрометирана, докато не ротирате ключа и не одитирате скорошната активност.
- Ротирайте ключа незабавно. В Supabase Dashboard отидете на Project Settings → API → Service role key → Reset. Старият ключ се анулира за секунди. Всеки сървърен код, използващ ключа, трябва да бъде актуализиран и преинсталиран преди ротацията да влезе в сила.
- Одитирайте скорошната активност в базата данни. Отворете Database → Logs в dashboard-а. Филтрирайте по последните 7 дни. Търсете необичайни
SELECT *заявки срещу таблици с PII, големиUPDATEилиDELETEизрази и заявки от IP адреси извън известната ви инфраструктура. Supabase логва заглавкатаx-real-ipна всяка заявка. - Проверете обектите в хранилището. Посетете Storage → Logs и прегледайте скорошните изтегляния на файлове. Изтекъл service-role ключ дава пълен достъп и до частни bucket-и.
- Премахнете ключа от source control. Дори след ротация, оставянето на JWT в git историята означава, че е откриваем в публичното repo. Използвайте
git filter-repoили BFG Repo-Cleaner, за да го изтриете от историята, след това force-push (предупредете сътрудниците първо). - Сканирайте отново след поправката. Изпълнете ново FixVibe сканиране срещу преинсталираното приложение. Откритието bundle-secrets трябва да изчезне. Потвърдете, че няма останал
service_roleJWT и никакъвsb_secret_*низ в който и да е chunk.
Предотвратяване на изтичането на първо място
Структурната поправка е дисциплина в именуването плюс предпазни механизми на ниво инструменти:
- Никога не поставяйте префикс
NEXT_PUBLIC_*,VITE_*или какъвто и да е друг префикс за вграждане в bundle на сервизния ключ. Конвенцията за именуване е границата — всяка рамка я зачита. - Дръжте сервизния ключ напълно извън
.envна машината на разработчика. Прочитайте го от мениджър на тайни (Doppler, Infisical, Vercel криптирани env vars) при deploy, никога не го 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 gate, който сканира build output-а. След
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 ключове?
Скенери на публични bundle-и обхождат нови деплои в рамките на минути. Изследователи са документирали работещи експлойти срещу нови Supabase проекти за по-малко от час от първото деплойване. Третирайте всяко излагане на service-role като 60-минутен прозорец, а не 60-дневен.
Достатъчно ли е ротирането на ключа, или трябва да приема ексфилтрация на данни?
Ротацията анулира изтеклия ключ, но не отменя вече извлечените данни. Ако таблиците ви съдържат PII, платежни данни или каквито и да е регулирани данни, може да имате задължение за уведомяване по GDPR (72 часа), CCPA или HIPAA. Одитирайте логовете и се консултирайте с правен съветник, ако одитът покаже подозрителен достъп.
Може ли RLS да ме защити, ако сервизният ключ изтече?
Не. Сигурността на ниво ред е напълно заобиколена от claim service_role. Това е по дизайн — ключът съществува точно за да позволи на backend кода да пропуска RLS за admin операции. Смекчаването е да се уверите, че ключът никога не достига контекст, в който нападател може да го прочете.
Прилага ли се това към новия модел на Supabase с публикуем / секретен ключ (<code>sb_publishable_</code> / <code>sb_secret_</code>)?
Да — идентичен клас риск. Ключът sb_secret_* е новият формат на секретния ключ, който замества service-role JWT за по-нови проекти. Всичко, носещо sb_secret_* в bundle, е също толкова катастрофално, колкото изтекъл service-role JWT. Детекторът bundle-secrets на FixVibe съответства на двете форми.
Какво ще кажете за anon / публикуемия ключ — безопасен ли е в bundle-а?
Да, по дизайн. Anon ключът е предназначен да живее в браузъра и е това, което използва всеки Supabase web клиент. Безопасността му зависи изцяло от това дали RLS е правилно конфигуриран на всяка публична таблица. Вижте статията Сканер за Supabase RLS за това какво да проверите.
Следващи стъпки
Изпълнете FixVibe сканиране срещу production URL — проверката bundle-secrets е безплатна, без регистрация и докладва излагане на service_role за по-малко от минута. Сдвоете това със статията Сканер за Supabase RLS, за да проверите дали RLS слоят си върши работата, и Контролен списък за сигурност на storage bucket на Supabase, за да заключите достъпа до файлове. За фон относно това защо AI инструментите генерират този клас изтичане толкова надеждно, прочетете Защо AI инструментите за кодиране оставят пропуски в сигурността.
