// docs / security guides / hardening
كيفية تأمين تطبيق مبني بأدوات الترميز بالذكاء الاصطناعي
دليل تقوية خطوة بخطوة للتطبيقات التي أنشأتها باستخدام Cursor أو Claude Code أو Lovable أو Bolt أو v0 أو Replit أو Windsurf. أربع مراحل: فهم سبب فشل التطبيقات التي تم إنشاؤها AI- بشكل مختلف، وإجراء تدقيق فوري لقاعدة التعليمات البرمجية، والتشدد في وقت النشر، ثم مواصلة المراقبة. رأي، سردي، مع مقتطفات حقيقية يمكنك نسخها.
لماذا تفشل التطبيقات التي تم إنشاؤها AI- بشكل مختلف
يمكن أن تكون التطبيقات المشفرة بـ Vibe آمنة. إنهم بحاجة إلى تصريح تدقيق إضافي لأن أوضاع الفشل هيكلية وليست مهملة:
- Assistants inline hardcoded keys. You ask for a fix to an auth error and get a pasted Supabase example that assumes a service-role client. The key ends up at the top of a page component. Both the anon client and the service client coexist; both ship.
- Generated servers default to permissive CORS. Generated Express / Fastify handlers often ship with
cors({ origin: '*' })because that's the fastest way to get a working preview. The middleware never gets a second pass. - Rules files get skipped. Firestore-backed projects generate the data model but rarely touch
firestore.rules. Test-mode rules let anyone read and overwrite data until someone replaces them. - RLS never enters the migration. A generated Supabase schema and CRUD surface use the anon key, but
ENABLE ROW LEVEL SECURITYnever enters the migration. Anonymous users can read or write any row. - Handlers trust IDs. A generated
GET /api/items/[id]reads the param and queries Postgres without verifying ownership. Active scans on a verified domain test for this (IDOR / BOLA).
التدقيق الفوري: grep قاعدة التعليمات البرمجية الخاصة بك لأنماط المخاطر
قبل أن تصلب أي شيء، ابحث عن ما تم كسره بالفعل. تستغرق كل هذه الخطوات أقل من دقيقة:
الأسرار ومفاتيح المزود
grep -RIn 'NEXT_PUBLIC_SUPABASE_SERVICE' src/
grep -RIn 'sk_live_\|pk_live_\|STRIPE_SECRET' src/
grep -RIn 'sk-ant-\|^sk-' src/ # Anthropic / OpenAI
grep -RIn 'AIza\|AKIA' src/ # Google / AWS
grep -RIn 'eyJh[A-Za-z0-9_-]\{20,\}' src/ # JWT-shaped stringsأي ضربة تحتاج إلى الحذف بالإضافة إلى تدوير المفتاح. لوحات معلومات Provider: Supabase → الإعدادات → API، Stripe → المطورون → API المفاتيح، وحدة تحكم Anthropic / OpenAI.
ضوابط الوصول إلى قاعدة البيانات
# Supabase migrations
grep -RIn 'CREATE TABLE public\.' supabase/migrations/
grep -RIn 'ENABLE ROW LEVEL SECURITY\|FORCE ROW LEVEL SECURITY' supabase/migrations/
# Firebase / Firestore
cat firestore.rules # confirm no `if true;` matchesيحتاج كل CREATE TABLE public.* إلى مطابقة ENABLE ROW LEVEL SECURITY وسياسة واحدة على الأقل. يجب أن تحدد قواعد Firestore نطاق القراءة إلى request.auth.uid.
المصادقة والتعامل مع الجلسة
grep -RIn 'getSession()' src/ # should be getUser() server-side
grep -RIn 'localStorage\.\(set\|get\)Item.*token' src/
grep -RIn 'jwt.verify.*\(noVerify\|skipVerify\)' src/يجب أن تستخدم المسارات التي يعرضها الخادم supabase.auth.getUser() — ويتم التحقق منها باستخدام الواجهة الخلفية. getSession() يقرأ ملف تعريف الارتباط الذي لم يتم التحقق منه. يمكن الوصول إلى الرموز المميزة الموجودة في localStorage بواسطة أي برنامج نصي يتم تشغيله على الصفحة.
الرؤوس والبرمجيات الوسيطة
# Confirm middleware location for src/ layouts
ls src/middleware.ts middleware.ts 2>&1
# Look for CSP and security headers
grep -RIn 'Content-Security-Policy\|Strict-Transport-Security' src/باستخدام التخطيط src/، يتم التقاط src/middleware.ts فقط. إذا كان ملف البرنامج الوسيط الخاص بك موجودًا في جذر المشروع، فإن Next.js يتجاهله بصمت ولن يعمل منطق تحديث المصادقة / CSP أبدًا.
تصلب في وقت النشر
بمجرد تنظيف المصدر، قم بتأمين كيفية وصول التطبيق إلى مرحلة الإنتاج.
الخطوة 1: بيئات منفصلة
Vercel: ثلاث بيئات - Production (مجال الإنتاج الخاص بك)، المعاينة (PR / النشر المرحلي)، التطوير (محلي). يحصل كل منها على مجموعة env-var الخاصة به. المفاتيح المباشرة Stripe / الأنثروبي / Supabase لا تصل أبدًا إلى المعاينة؛ لا تصل مفاتيح المعاينة أبدًا إلى Production. تدفع الفروع للمعاينة تلقائيًا؛ دمج إلى main نشر إلى Production.
الخطوة 2: صارمة CSP عبر البرامج الوسيطة
أنشئ رقمًا لكل طلب، ثم أدخله في Content-Security-Policy. Next.js يطبق الرقم تلقائيًا على علامات البرنامج النصي الخاصة به عندما تقوم بتعيين رأس الطلب x-nonce.
// src/middleware.ts
import { NextResponse, type NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const nonce = crypto.randomUUID().replace(/-/g, '');
const csp = [
`script-src 'nonce-${nonce}' 'strict-dynamic'`,
`style-src 'self' 'unsafe-inline'`,
`img-src 'self' data: https:`,
`connect-src 'self' https://*.supabase.co`,
`object-src 'none'`,
`base-uri 'self'`,
`frame-ancestors 'none'`,
].join('; ');
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-nonce', nonce);
const response = NextResponse.next({ request: { headers: requestHeaders } });
response.headers.set('Content-Security-Policy', csp);
response.headers.set('X-Content-Type-Options', 'nosniff');
response.headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
return response;
}
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};الخطوة 3: فرض RLS على كل طاولة عامة
RLS isn't enabled by default on tables you create in SQL or migrations. Enable it on every exposed table and pair each one with explicit policies per role — that is what stops the anon and authenticated roles. FORCE only makes the table owner obey RLS too.
-- supabase/migrations/XXXX_rls.sql
alter table public.profiles enable row level security;
alter table public.profiles force row level security;
create policy "profiles: read own"
on public.profiles for select
using (auth.uid() = id);
create policy "profiles: update own"
on public.profiles for update
using (auth.uid() = id)
with check (auth.uid() = id);الخطوة 4: التحقق من مصادقة الخادم فقط على كل مسار API
يتحقق كل مسار API لتغيير الحالة من جانب خادم المتصل باستخدام supabase.auth.getUser(). يصبح كائن المستخدم مصدر الحقيقة لـ user_id — لا تثق أبدًا في نص الطلب لتعيينه.
// src/app/api/items/route.ts
import { NextResponse, type NextRequest } from 'next/server';
import { createClient } from '@/lib/supabase/server';
export async function POST(request: NextRequest) {
const supabase = await createClient();
const { data: { user } } = await supabase.auth.getUser();
if (!user) return NextResponse.json({ error: 'unauthorized' }, { status: 401 });
const body = await request.json();
const { data, error } = await supabase
.from('items')
.insert({ ...body, user_id: user.id }) // server-supplied, not from body
.select()
.single();
if (error) return NextResponse.json({ error: error.message }, { status: 400 });
return NextResponse.json(data);
}الخطوة 5: عكس تحليلاتك
Proxying التحليلات من خلال المجال الخاص بك تتجنب أدوات حظر الإعلانات وتسمح لـ CSP connect-src 'self' بالبقاء محدودًا. يعمل نفس النمط مع PostHog وPlusible وUmami وأحواض الأحداث المخصصة.
// src/app/api/posthog/[...path]/route.ts
import { type NextRequest } from 'next/server';
const UPSTREAM = 'https://us.i.posthog.com';
export async function POST(req: NextRequest, { params }: { params: Promise<{ path: string[] }> }) {
const { path } = await params;
const url = `${UPSTREAM}/${path.join('/')}`;
return fetch(url, {
method: 'POST',
headers: { 'content-type': req.headers.get('content-type') ?? 'application/json' },
body: await req.text(),
});
}الخطوة 6: حماية إعادة التوجيه المفتوحة على ارتداد ما بعد المصادقة
عادةً ما تقبل تدفقات تسجيل الدخول/التسجيل معلمة استعلام next. ارفض أي شيء ليس مسارًا لنفس الموقع — ابدأ بـ / ولا // أبدًا (نسبي للبروتوكول، يرسل المستخدمين خارج الموقع).
function safeNext(raw: string | null): string {
if (!raw) return '/dashboard';
if (!raw.startsWith('/') || raw.startsWith('//')) return '/dashboard';
return raw;
}مستمر: المراقبة وإعادة المسح
يحدث الانجراف عند كل عملية نشر. تعامل مع الأمان كحلقة، وليس قائمة مرجعية تنتهي منها.
تحقق من مجال الإنتاج الخاص بك
Dashboard → Domains → add your production domain → DNS TXT or HTTP-file verification. Active scans require Hobby or above; scheduled re-scans require Pro or Unlimited.
جدولة عمليات إعادة الفحص السلبية
Scheduled re-scans are available on Pro and Unlimited for verified domains. Free and Hobby scans are manual. Scheduled scans use your plan allowance. Configure completion email preferences and a scan.completed webhook if needed.
# Or from CI, via the REST API:
curl -X POST https://fixvibe.app/api/v1/scans \
-H "authorization: Bearer $FIXVIBE_TOKEN" \
-H "content-type: application/json" \
-d '{"target":"https://your-app.com"}'تمكين API- عمليات الفحص النشطة (اختياري)
إذا كنت تريد فحصًا نشطًا آليًا (SQLi / XSS / IDOR المشي / وما إلى ذلك)، فقم بتشغيله لكل مجال في Dashboard → Domains → API active. التفويض دائم، وتنتهي مدته 90 يومًا، وقابل للإلغاء على الفور. قم بالاقتران مع خطاف الويب scan.active_api.first_used حتى يصل أول فحص نشط آلي بعد التمكين إلى تنبيهك.
قم بتوصيل النتائج إلى سير العمل AI الخاص بك
On Hobby or above, create an API token at Account → API tokens and configure the MCP server (/docs/mcp) in your coding tool. Ask your agent to run an authorized scan and inspect the highest-severity findings. Code fixes can use remediation prompts; provider and DNS fixes may need manual operator steps.
كشف التهديدات المباشرة (Unlimited)
Periodic certificate-transparency, DNS, JS-bundle, and threat-intelligence checks report observed changes on supported signals. Alerts depend on successful polling and source availability; they do not establish continuous or complete security coverage.
أنماط الفشل الحقيقية وإصلاحاتها
Five common patterns in AI-generated apps, each with the actual fix:
- مفتاح دور الخدمة في مكون العميل
Symptom: FixVibe reports an exposed Supabase service-role key on the production URL. Cause: an autocomplete pasted
createClient(URL, SERVICE_ROLE_KEY)into a React component. Fix: move the service client tosrc/lib/supabase/service.tswithimport 'server-only'at the top; create a parallelsrc/lib/supabase/client.tsusing the anon key for client-side use; rotate the service-role key via Supabase Studio. - تركت قواعد Firestore في وضع الاختبار
Symptom: a high-severity open Firebase rules finding. Cause: generated rules read
allow read, write: if request.time < timestamp.date(2026, 6, 1);— a time-bounded "allow all". Fix: scope each rule to the authenticated user —match /users/{userId}/posts/{postId} { allow read, write: if request.auth.uid == userId; }— and re-deployfirebase deploy --only firestore:rules. - مسموح CORS بالبقاء في مرحلة الإنتاج
Symptom: a high-severity CORS misconfiguration finding. Cause: generated Express middleware:
app.use(cors({ origin: '*' })). Fix: allowlist your frontend origin:app.use(cors({ origin: ['https://your-app.com'], credentials: true })). For Next.js API routes, setAccess-Control-Allow-Originexplicitly in the response. - RLS ممكّن ولكن ليس قسريًا
Symptom: FixVibe reports that anonymous visitors can read a public table even though RLS looks enabled in the dashboard. Cause: RLS is on, but a policy such as
USING (true)lets theanonrole through, or the migration that tightened it never ran in production. Fix: replace the permissive policy with one scoped toauth.uid(), apply the migration, and re-scan. - معرفات غير موقعة IDOR- قابلة للمشي
Symptom: an active scan on your verified domain reports that one user can read another user's records at
/api/items/1,/api/items/2, ... Cause: the API handler trusts the path param and queries Postgres without an ownership predicate. Fix: add.eq('user_id', user.id)on every read query, or move to signed URLs / UUIDs scoped under/api/users/[uid]/items/[id].
حلقة الأمان ذات الرمز الحيوي
الهدف ليس الأمن المثالي؛ إنها تقضي على الثمار المنخفضة التي تفتقدها الأدوات AI باستمرار حتى تتمكن من الاستمرار في الشحن بسرعة.
- Generate fast - استخدم Cursor، Claude Code، Lovable، Bolt. هذه هي النقطة.
- Audit immediately - قم بتشغيل مجموعة grep أعلاه، وتحقق من RLS، وتحقق من CSP، وراجع حدود المصادقة.
- Harden at deploy - البرامج الوسيطة، فصل البيئة، CSP nonce، HSTS، التحقق من مصادقة الخادم فقط.
- Monitor — FixVibe سلبي يوميًا، ونشط أسبوعيًا على نطاق تم التحقق منه، وخطافات الويب إلى Slack، واكتشاف التهديدات على Unlimited.
- Fix fast — use FixVibe coding-agent prompts for code/config findings and operator steps for DNS, provider, secret-rotation, or manual-review findings. Re-deploy, re-scan, close the loop.
الخطوات التالية
للحصول على الخلفية المفاهيمية لـ DAST مقابل SAST ولماذا تحتاج التطبيقات التي تم إنشاؤها AI- إلى المسح الضوئي الخاص بها، اقرأ AI-generated code security scanning. للحصول على مرجع سريع لمراجعة ما قبل الشحن، راجع vibe coding security checklist.
