FixVibe

// docs / baas security / supabase service role exposure

افشای کلید service role Supabase در جاوااسکریپت: معنای آن و چگونه آن را پیدا کنیم

کلید service role Supabase کلید اصلی پایگاه‌داده شماست. هر کسی که آن را در اختیار داشته باشد، Row-Level Security را دور می‌زند، می‌تواند هر ستون از هر جدولی را بخواند و هر چه بخواهد بنویسد یا حذف کند. این کلید برای آن طراحی شده که منحصراً در کد سمت‌سرور باشد — هرگز در مرورگر نباشد. وقتی یک ابزار کدنویسی هوش مصنوعی آن را به بسته جاوااسکریپت می‌فرستد، پایگاه‌داده شما در عمل عمومی است. این مقاله شکل JWT که یک کلید نشت‌یافته را شناسایی می‌کند، سه الگوی ابزار هوش مصنوعی که نشت تولید می‌کنند، آنچه در ساعت اول پس از شناسایی باید کرد، و چگونگی اسکن خودکار آن پیش از کاربران را توضیح می‌دهد.

کلید service role چیست

Supabase برای هر پروژه دو کلید متفاوت صادر می‌کند: کلید anon (که در پروژه‌های جدیدتر کلید publishable نیز نامیده می‌شود) و کلید service_role. هر دو JSON Web Token هستند که با راز JWT پروژه شما امضا شده‌اند. تفاوت در ادعای role داخل payload JWT است — anon برای کلید عمومی، service_role برای کلید اصلی. PostgREST، Supabase Storage و Supabase Auth همگی وقتی ادعای service_role را می‌بینند به حالت دور زدنِ همه چیز می‌روند.

هر کلید Supabase را در jwt.io رمزگشایی کنید و به payload نگاه کنید. شکل یک JWT با service-role قابل اشتباه گرفته نیست:

Payload رمزگشایی‌شده یک JWT با service-role (در بلوک نحوی‌رنگ‌شده زیر نشان داده شده).

json
{
  "iss": "supabase",
  "ref": "[project-ref]",
  "role": "service_role",
  "iat": 1700000000,
  "exp": 2000000000
}

پروژه‌های جدیدتر Supabase کلیدهای سبک secret با پیشوند sb_secret_ به‌جای JWT صادر می‌کنند. رفتار یکسان است — هر چیزی که sb_secret_ در یک بسته عمومی حمل کند به همان اندازه فاجعه‌بار است.

ابزارهای کدنویسی هوش مصنوعی چگونه کلید service role را افشا می‌کنند

ما همان سه الگو را در هزاران اپلیکیشن vibe-coded دیده‌ایم. هر کدام با درخواست کمک یک توسعه‌دهنده از ابزار هوش مصنوعی شروع و به جاسازی کلید سرویس درون یک بسته ختم می‌شود.

الگوی ۱: یک فایل .env با پیشوند NEXT_PUBLIC_

توسعه‌دهنده از ابزار هوش مصنوعی می‌خواهد "Supabase را راه‌اندازی کند" و یک .env با هر دو کلید را می‌پذیرد. ابزار هوش مصنوعی — که روی پیکره‌ای آموزش دیده که اکثر متغیرهای محیطی از طریق NEXT_PUBLIC_* در دسترس قرار می‌گیرند — هر دو را با NEXT_PUBLIC_ پیشوند می‌گذارد. Next.js هر چیزی که با این پیشوند مطابقت داشته باشد را در زمان build داخل بسته کلاینت قرار می‌دهد. به Vercel منتشر کنید، و کلید سرویس در main.[hash].js قرار دارد.

الگوی ۲: کلید اشتباه در فراخوانی createClient

توسعه‌دهنده هر دو کلید را در یک فایل config.ts که هوش مصنوعی تولید کرده می‌چسباند، و هوش مصنوعی فراخوانی سمت‌مرورگر createClient() را به اشتباه با process.env.SUPABASE_SERVICE_ROLE_KEY پر می‌کند. ساخت آن متغیر را وارد می‌کند، و JWT در بسته قرار می‌گیرد.

الگوی ۳: کلید service-role در اسکریپت‌های seed به‌صورت hardcoded

توسعه‌دهنده از ابزار هوش مصنوعی می‌خواهد اسکریپتی بنویسد که پایگاه‌داده را seed کند. هوش مصنوعی کلید service-role را مستقیماً در فایل hardcode می‌کند (به‌جای خواندن از محیط)، فایل را در ریپو commit می‌کند، و ریپوی عمومی GitHub یا مسیر /scripts/seed.js اپلیکیشن مستقرشده اکنون کلید را ارائه می‌دهد.

اسکن بسته FixVibe چگونه نشت را تشخیص می‌دهد

فحص bundle-secrets در FixVibe هر فایل جاوااسکریپتی که اپلیکیشن مستقرشده به آن ارجاع می‌دهد را دانلود می‌کند — chunkهای ورودی، chunkهای lazy-load، web workers، service workers — و آن‌ها را از طریق تشخیصگری اجرا می‌کند که هر چیزی با شکل JWT (eyJ[base64-header].eyJ[base64-payload].[signature]) را رمزگشایی می‌کند. اگر payload رمزگشایی‌شده شامل "role": "service_role" باشد، اسکن آن را به‌عنوان یک یافته بحرانی با مسیر فایل و خط دقیق که کلید در آن ظاهر می‌شود گزارش می‌دهد. همان فحص الگوی جدیدتر sb_secret_* را نیز با پیشوند تطبیق می‌دهد.

اسکن هرگز با کلید کشف‌شده احراز هویت نمی‌کند. شکل آن را شناسایی و نشت را گزارش می‌کند — استفاده از کلید برای اثبات قابل بهره‌برداری بودن، دسترسی غیرمجاز به پایگاه‌داده شما خواهد بود. اثبات در خود payload JWT است.

شناسایی شد — در ساعت اول چه باید کرد

یک کلید service role نشت‌یافته یک اضطرار زمان اجرا است. فرض کنید کلید کشف شده — مهاجمان بسته‌های عمومی را در زمان واقعی پایش می‌کنند. تا زمانی که کلید را چرخش نداده‌اید و فعالیت‌های اخیر را بررسی نکرده‌اید، پایگاه‌داده را در وضعیت compromise‌شده تلقی کنید.

  1. کلید را فوراً چرخش دهید. در داشبورد Supabase به Project Settings → API → Service role key → Reset بروید. کلید قدیمی در عرض چند ثانیه بی‌اعتبار می‌شود. هر کد سمت‌سرور که از کلید استفاده می‌کند باید پیش از فرود چرخش به‌روزرسانی و دوباره مستقر شود.
  2. فعالیت‌های اخیر پایگاه‌داده را بررسی کنید. Database → Logs را در داشبورد باز کنید. روی ۷ روز گذشته فیلتر کنید. به دنبال کوئری‌های غیرعادی SELECT * روی جدول‌های دارای PII، دستورهای بزرگ UPDATE یا DELETE، و درخواست‌ها از IPهای خارج از زیرساخت شناخته‌شده شما بگردید. Supabase هدر x-real-ip را روی هر درخواست ثبت می‌کند.
  3. اشیای ذخیره‌سازی را بررسی کنید. Storage → Logs را ببینید و دانلودهای فایل اخیر را بررسی کنید. یک کلید service-role نشت‌یافته دسترسی دور زدنِ همه چیز را به سطل‌های خصوصی نیز می‌دهد.
  4. کلید را از کنترل منبع حذف کنید. حتی پس از چرخش، باقی گذاشتن JWT در تاریخچه git یعنی هنوز در ریپوی عمومی قابل کشف است. از git filter-repo یا BFG Repo-Cleaner برای پاک کردن آن از تاریخچه استفاده کنید، سپس force-push کنید (ابتدا به همکاران اطلاع دهید).
  5. پس از رفع، دوباره اسکن کنید. یک اسکن تازه FixVibe را روی اپلیکیشن دوباره مستقرشده اجرا کنید. یافته bundle-secrets باید پاک شود. تأیید کنید که هیچ JWT با service_role و هیچ رشته sb_secret_* در هیچ chunk باقی نمانده است.

پیشگیری از نشت در همان ابتدا

راه‌حل ساختاری انضباط نام‌گذاری به‌علاوه نگهبان‌های سطح ابزار است:

  • هرگز کلید سرویس را با NEXT_PUBLIC_*، VITE_* یا هر پیشوند bundle-inlining دیگری پیشوند ندهید. قرارداد نام‌گذاری همان مرز است — هر فریم‌ورک به آن احترام می‌گذارد.
  • کلید سرویس را به‌طور کلی روی ماشین توسعه‌دهنده از .env دور نگه دارید. آن را از یک مدیر اسرار (Doppler، Infisical، متغیرهای محیطی رمزگذاری‌شده Vercel) در زمان استقرار بخوانید، هرگز به‌صورت محلی 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 را اسکن می‌کند. پس از next build، خروجی .next/static/chunks/ را برای رشته service_role grep کنید. اگر چیزی منطبق شد build را شکست دهید.
bash
# 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

سؤالات متداول

مهاجمان چقدر سریع کلیدهای service-role نشت‌یافته Supabase را پیدا می‌کنند؟

اسکنرهای بسته عمومی استقرارهای جدید را در عرض چند دقیقه می‌کاوند. محققان اکسپلویت‌های موفق علیه پروژه‌های Supabase جدید را در کمتر از یک ساعت از اولین استقرار مستند کرده‌اند. هر افشای service-role را به‌عنوان یک پنجره ۶۰ دقیقه‌ای تلقی کنید، نه ۶۰ روزه.

آیا چرخش کلید کافی است یا باید فرض کنم داده‌ها بیرون کشیده شده‌اند؟

چرخش کلید نشت‌یافته را بی‌اعتبار می‌کند ولی داده‌هایی که قبلاً برداشته شده‌اند را بازنمی‌گرداند. اگر جدول‌های شما شامل PII، داده‌های پرداخت یا هر داده تنظیم‌شده‌ای باشند، ممکن است طبق GDPR (۷۲ ساعت)، CCPA یا HIPAA تعهد اطلاع‌رسانی داشته باشید. لاگ‌ها را بررسی کنید و اگر بررسی دسترسی مشکوکی را نشان داد با مشاور حقوقی مشورت کنید.

آیا RLS می‌تواند مرا اگر کلید service-role نشت کند محافظت کند؟

خیر. امنیت در سطح ردیف کاملاً توسط ادعای service_role دور زده می‌شود. این طراحی است — این کلید دقیقاً برای آن وجود دارد که کد بک‌اند بتواند برای عملیات admin از RLS عبور کند. راه مقابله این است که اطمینان حاصل کنید کلید هرگز به زمینه‌ای نمی‌رسد که مهاجم بتواند آن را بخواند.

آیا این به مدل کلید publishable / secret جدید Supabase (<code>sb_publishable_</code> / <code>sb_secret_</code>) نیز اعمال می‌شود؟

بله — کلاس ریسک یکسان. کلید sb_secret_* فرمت جدید secret-key است که برای پروژه‌های جدیدتر جایگزین JWT service-role شده است. هر چیزی که sb_secret_* را در یک بسته حمل کند به همان اندازه یک JWT service-role نشت‌یافته فاجعه‌بار است. تشخیصگر bundle-secrets در FixVibe هر دو شکل را تطبیق می‌دهد.

درباره کلید anon / publishable چه — آیا در بسته امن است؟

بله، طبق طراحی. کلید anon قرار است در مرورگر باشد و آن چیزی است که هر کلاینت وب Supabase استفاده می‌کند. ایمنی آن کاملاً به درست پیکربندی شدن RLS روی هر جدول عمومی بستگی دارد. برای آنچه باید بررسی کنید مقاله اسکنر Supabase RLS را ببینید.

گام‌های بعدی

یک اسکن FixVibe را روی URL تولیدی خود اجرا کنید — فحص bundle-secrets رایگان است، بدون نیاز به ثبت‌نام، و افشای service_role را در کمتر از یک دقیقه گزارش می‌دهد. این را با مقاله اسکنر Supabase RLS ترکیب کنید تا تأیید کنید لایه RLS کار خود را انجام می‌دهد، و چک‌لیست امنیت سطل ذخیره‌سازی Supabase را برای قفل کردن دسترسی به فایل اضافه کنید. برای پس‌زمینه‌ای از این‌که چرا ابزارهای هوش مصنوعی این کلاس نشت را با چنین قابلیت اطمینانی تولید می‌کنند، چرا ابزارهای کدنویسی هوش مصنوعی شکاف‌های امنیتی به جای می‌گذارند را بخوانید.

// سطح baas خود را اسکن کنید

جدول باز را پیش از دیگران پیدا کنید.

یک آدرس URL از محیط تولید وارد کنید. FixVibe ارائه‌دهندگان BaaS که اپلیکیشن شما با آن‌ها صحبت می‌کند را شناسایی می‌کند، نقاط پایانی عمومی آن‌ها را اثرانگشت‌برداری می‌کند و گزارش می‌دهد که یک کلاینت بدون احراز هویت چه چیزی می‌تواند بخواند یا بنویسد. رایگان، بدون نصب، بدون کارت اعتباری.

  • پلن رایگان — ۳ اسکن در ماه، بدون نیاز به کارت اعتباری برای ثبت‌نام.
  • اثرانگشت‌برداری غیرفعال BaaS — نیازی به تأیید دامنه نیست.
  • Supabase، Firebase، Clerk، Auth0، Appwrite و بیشتر.
  • پرامپت‌های اصلاحی هوش مصنوعی روی هر یافته — کافی است در Cursor / Claude Code جای‌گذاری کنید.
یک اسکن رایگان BaaS اجرا کنید

نیازی به ثبت‌نام نیست

افشای کلید service role Supabase در جاوااسکریپت: معنای آن و چگونه آن را پیدا کنیم — Docs · FixVibe