
ماسح أمان ثابت محلي لتطبيقات Next.js وSupabase وStripe: 24 فحصًا قائمًا على AST للمفاتيح المسربة، وغياب RLS والصلاحيات، وخطافات الويب غير الآمنة. واجهة سطر أوامر (CLI) وإجراء GitHub (GitHub Action).
فحص أمني محلي مجاني لتطبيقات Next.js + Supabase + Stripe: المفاتيح المسرّبة، وRLS والصلاحيات المفقودة، وخطافات Stripe webhooks غير الآمنة.
وكيل الذكاء الاصطناعي الخاص بك أطلق التطبيق. فهل أطلق معه أيضًا مفتاح Stripe السري الخاص بك، أو جدولًا بدون RLS، أو webhook يمكن لأي شخص استدعاؤه؟ أمر واحد يكشف ذلك، محليًا، في أقل من ثانية.
npx github:edtrackai/nextjs-supabase-stripe-security-checker /path/to/your/app
إنه ليس على npm بعد، لذا يشغّله npx مباشرة من مستودع GitHub هذا (يتطلب Node 18+ وgit).
- uses: edtrackai/nextjs-supabase-stripe-security-checker@v0
with:
fail-on: high
سير العمل الكامل والأذونات موضّحة أدناه وفي docs/github-action.md.
مدقّق Supabase RLS · أمان Stripe webhook · فحص أمان Next.js · منح Supabase Data API (42501)

git clone https://github.com/edtrackai/nextjs-supabase-stripe-security-checker.git
cd nextjs-supabase-stripe-security-checker && npm install
node bin/nss-security-check.js /path/to/your/app
Node 18 أو أحدث. هناك اعتمادية واحدة (@babel/parser). مجاني ومرخّص بموجب MIT، ولا يحتاج إلى حساب، ولا يجري أي اتصالات شبكية ولا يرفع شيفرتك أبدًا.
--fail-on=high يخرج بالرمز 1، و--json يعطي مخرجات قابلة للقراءة آليًا.إعلان (مدفوع، نفس المؤلف): تريد الإصلاحات؟ Launch Audit (12 دولارًا بالإضافة إلى ضريبة القيمة المضافة حيث ينطبق) يضيف 28 فحصًا، ووكيل تدقيق AI بدون أدوات Edit أو Write، وخطة إصلاح file:line.
| العلم | ما يفعله |
|---|---|
--json | مخرجات قابلة للقراءة آليًا: {tool, version, root, filesScanned, counts, findings[]} |
--fail-on=<sev> | يخرج بالرمز 1 إذا كانت أي نتيجة عند critical / high / medium / low أو أعلى (none لا يفشل أبدًا). يخرج بالرمز 2 عند وسائط خاطئة. |
--list | يطبع كتالوج الفحوصات |
--quiet | يحذف سطر التذييل المكوّن من سطر واحد حول الأدوات المدفوعة (يُطبع إلى stderr على الطرفية فقط؛ يُعطّل أيضًا مع NO_PROMO=1 أو CI أو GITHUB_ACTIONS) |
--help | الاستخدام |
في CI: node path/to/bin/nss-security-check.js . --fail-on=high، أو استخدم GitHub Action (ملخص المهمة، التعليقات التوضيحية، تعليق PR لاصق واحد، فقط GITHUB_TOKEN). راجع سير العمل النموذجي والأذونات في docs/github-action.md.
# .github/workflows/security-check.yml
name: Security check
on: [pull_request]
permissions:
contents: read
pull-requests: write # only for the PR comment; drop it with comment: false
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: edtrackai/nextjs-supabase-stripe-security-checker@v0 # or pin @v0.5.0 / a commit SHA
with:
path: .
fail-on: high
التغييرات مدرجة في CHANGELOG.md (الإصدار 0.5.0 يضيف الـ Action).
| المعرّف | الخطورة | المجال | الفحص |
|---|---|---|---|
| K1 | حرجة | المفاتيح | مفتاح Stripe سري/مقيّد حيّ (sk_live_/rk_live_) في الشيفرة المصدرية، بما في ذلك المفاتيح المقسمة بـ + (الأدلة محجوبة) |
| K2 | حرجة | المفاتيح | متغيّر NEXT_PUBLIC_ يبدو سرّيًا (service role، مفتاح سري، سرّ webhook…) |
| K3 | حرجة | المفاتيح | ملف .env بقيم متتبَّعة بواسطة git |
| K4 | حرجة | المفاتيح | سرّ خادم أو عميل Supabase الإداري مستخدم في مكوّن "use client" |
| A1 | عالية | المصادقة | الوثوق بـ auth.getSession() على الخادم بدلًا من getUser()/getClaims() |
| A2 | عالية | المصادقة | Server Action يكتب بيانات دون فحص مصادقة |
| A3 | عالية | المصادقة | مسار API (POST/PUT/PATCH/DELETE) يكتب بيانات دون فحص مصادقة (تُستثنى مسارات webhook وcron والمصادقة) |
| A4 | عالية | المصادقة | استعلام عميل إداري بمعرّف مورَّد من الطلب دون مرشّح مالك (IDOR) |
| A5 | متوسطة | المصادقة | إعادة توجيه مفتوحة من معامل استعلام |
| R1 | حرجة | RLS | جدول مُنشأ دون أمان مستوى الصفوف |
| R2 | حرجة | RLS | سياسة كتابة بـ using (true) / with check (true) |
| R3 | عالية | RLS | سياسة تتيح لدور anon الكتابة |
| R4 | عالية | RLS | دالة security definer دون search_path ثابت |
| R5 | متوسطة | RLS | جدول في public دون GRANT صريح. أعلنت Supabase أنها ستوقف المنح الافتراضية على جداول public الجديدة اعتبارًا من 30 أكتوبر 2026، لكن في أواخر أغسطس كتب أحد مشرفي Supabase CLI (supabase/cli PR #6337) أن تغيير الافتراضي السابق "لم يُطبَّق قط" وأن المشاريع المستضافة كانت لا تزال تمنح تلقائيًا، لذا قد يتغيّر التاريخ: تحقّق مما يفعله مشروعك أنت. دون منح، تُرجع Data API الرمز 42501 |
| R6 | عالية | RLS | grant ... on all tables in schema public / alter default privileges ... grant الشامل لـ anon/authenticated (الإصلاح السريع لـ 42501 الذي يكشف أيضًا الجداول دون RLS) |
| S1 | حرجة | Stripe | Webhook دون التحقق من التوقيع (constructEvent) |
| S2 | حرجة | Stripe | Webhook يحلّل request.json() بدلًا من الجسم الخام |
| S3 | متوسطة | Stripe | Webhook دون ضمان عدم التكرار (idempotency) على event.id |
| S4 | عالية | Stripe | سعر أو مبلغ الدفع مأخوذ من الطلب |
| S5 | عالية | Stripe | منح الوصول في صفحة نجاح الدفع بدلًا من الـ webhook |
| S6 | متوسطة | Stripe | إزالة تكرار الـ webhook التي قد تبتلع حدثًا فاشلًا: تُتخطّى التكرارات دون حالة pending/completed |
| S7 | منخفضة | Stripe | قراءة فترة الفوترة من items.data[0] (خاطئة للاشتراكات متعددة العناصر منذ API 2025-03-31.basil) |
| H1 | متوسطة | التقوية | لا ترويسات أمان في next.config |
| H2 | متوسطة | التقوية | dangerouslySetInnerHTML بقيمة غير حرفية |
fixtures/vulnerable-app يُفعّل جميع الفحوصات الـ 23 القائمة على الملفات، وتؤكد الاختبارات كلًّا منها في الملف المتوقع. يُختبر K3 على مستودع git مؤقت.fixtures/clean-app (تطبيق مرجعي مقوّى) وfixtures/near-miss (شيفرة آمنة تبدو كأنها ترتكب كل خطأ: webhooks بالجسم الخام مع idempotency بحالة pending/completed، بحث عن الفترة آمن متعدد العناصر، إعادة توجيه محروسة، استعلامات إدارية مرشّحة بالمالك، select using (true)، JSON-LD) يجب أن ينتجا 0 نتائج.npm test يشغّل حزمة node:test، بما في ذلك أعلام CLI وأكواد الخروج. npm run smoke يعطي ملخصًا من سطر واحد.