FixVibe

// docs / security guides / hardening

Cara mengamankan aplikasi yang dibangun dengan alat coding AI

Panduan pengerasan langkah demi langkah untuk aplikasi yang Anda buat dengan Cursor, Claude Code, Lovable, Bolt, v0, Replit, atau Windsurf. Empat fase: pahami mengapa aplikasi yang dihasilkan AI- mengalami kegagalan secara berbeda, segera jalankan audit basis kode, lakukan penguatan pada waktu penerapan, lalu terus pantau. Berpendapat, naratif, dengan cuplikan nyata yang dapat Anda salin.

Mengapa aplikasi yang dihasilkan AI- gagal secara berbeda

Aplikasi berkode getaran bisa jadi aman. Mereka memerlukan izin audit ekstra karena mode kegagalannya bersifat struktural, bukan sembarangan:

  • Cursor inlines hardcoded keys. Anda meminta Cursor untuk "memperbaiki kesalahan autentikasi", dan ia menempelkan contoh Supabase yang mengasumsikan klien peran layanan. Kuncinya berakhir di bagian atas komponen halaman. Baik klien segera dan klien layanan hidup berdampingan; kedua kapal.
  • Claude Code defaults to permissive CORS. Generated Express / Fastify handler dikirimkan bersama cors({ origin: '*' }) karena itulah cara tercepat untuk mendapatkan pratinjau yang berfungsi. Middleware tidak pernah mendapat izin kedua.
  • Lovable and v0 skip the rules file. Proyek yang didukung Firestore menghasilkan model data tetapi jarang menyentuh firestore.rules. Aturan mode pengujian berakhir secara diam-diam dan mengunci database tanpa peringatan kepada pengguna.
  • Bolt skips RLS migrations. Bolt menghasilkan skema Supabase dan permukaan CRUD yang menggunakan kunci segera. ENABLE ROW LEVEL SECURITY tidak pernah memasuki migrasi. Pengguna anonim dapat membaca atau menulis baris mana pun.
  • Windsurf trusts unsigned IDs. Dihasilkan GET /api/items/[id] membaca param dan menanyakan Postgres tanpa memverifikasi kepemilikan. Pola ini cukup umum sehingga probe aktif active.idor-walking memunculkannya dalam satu pemindaian.

Audit langsung: ambil basis kode Anda untuk mengetahui pola risiko

Sebelum Anda mengeraskan apa pun, temukan apa yang sudah rusak. Grep ini masing-masing membutuhkan waktu kurang dari satu menit:

Rahasia dan kunci penyedia

bash
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

Setiap pukulan memerlukan penghapusan ditambah rotasi kunci. Dasbor Provider: Supabase โ†’ Pengaturan โ†’ API, Stripe โ†’ Pengembang โ†’ API kunci, konsol Antropik / OpenAI.

Kontrol akses basis data

bash
# 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

Setiap CREATE TABLE public.* memerlukan ENABLE ROW LEVEL SECURITY yang cocok dan setidaknya satu kebijakan. Aturan Firestore harus membaca cakupan hingga request.auth.uid.

Penanganan autentikasi dan sesi

bash
grep -RIn 'getSession()' src/   # should be getUser() server-side
grep -RIn 'localStorage\.\(set\|get\)Item.*token' src/
grep -RIn 'jwt.verify.*\(noVerify\|skipVerify\)' src/

Rute yang dirender server harus menggunakan supabase.auth.getUser() โ€” rute ini diverifikasi dengan backend. getSession() membaca cookie yang belum diverifikasi. Token di localStorage dapat diakses oleh skrip apa pun yang berjalan di halaman.

Header dan middleware

bash
# 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/

Dengan tata letak src/, hanya src/middleware.ts yang diambil. Jika file middleware Anda berada di root proyek, Next.js mengabaikannya secara diam-diam dan logika CSP / auth-refresh Anda tidak pernah berjalan.

Pengerasan pada waktu penerapan

Setelah sumber bersih, kunci cara aplikasi mencapai produksi.

Langkah 1: Pisahkan lingkungan

Vercel: tiga lingkungan โ€” Production (domain produksi Anda), Pratinjau (PR / penerapan pementasan), Pengembangan (lokal). Masing-masing mendapatkan set env-varnya sendiri. Kunci live Stripe / Antropik / Supabase tidak pernah mencapai Pratinjau; Kunci pratinjau tidak pernah mencapai Production. Cabang mendorong ke Pratinjau secara otomatis; bergabung ke main disebarkan ke Production.

Langkah 2: Ketat CSP melalui middleware

Hasilkan nonce per permintaan, lalu masukkan ke Content-Security-Policy. Next.js menerapkan nonce secara otomatis ke tag skripnya sendiri ketika Anda menyetel header permintaan x-nonce.

ts
// 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).*)'],
};

Langkah 3: Paksa RLS di setiap tabel publik

RLS tidak diaktifkan secara default dan tidak diterapkan untuk pemilik tabel kecuali Anda FORCE mengaktifkannya. Pasangkan setiap tabel dengan kebijakan eksplisit per peran.

sql
-- 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);

Langkah 4: Verifikasi autentikasi khusus server pada setiap rute API

Setiap rute API yang mengubah status memverifikasi sisi server pemanggil dengan supabase.auth.getUser(). Objek pengguna menjadi sumber kebenaran untuk user_id โ€” jangan pernah mempercayai badan permintaan untuk menyetelnya.

ts
// 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);
}

Langkah 5: Balikkan proxy analisis Anda

Promelakukan analisis melalui domain Anda sendiri untuk menghindari pemblokir iklan dan membuat CSP connect-src 'self' Anda tetap sempit. Pola yang sama berfungsi untuk PostHog, Masuk Akal, Umami, acara khusus tenggelam.

ts
// 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(),
  });
}

Langkah 6: Penjaga pengalihan terbuka pada pantulan pasca-authentikasi

Alur proses masuk/pendaftaran biasanya menerima parameter kueri next. Tolak apa pun yang bukan jalur situs yang sama โ€” mulai dengan / dan jangan pernah // (protokol-relatif, mengirim pengguna ke luar situs).

ts
function safeNext(raw: string | null): string {
  if (!raw) return '/dashboard';
  if (!raw.startsWith('/') || raw.startsWith('//')) return '/dashboard';
  return raw;
}

Sedang berlangsung: pemantauan dan pemindaian ulang

Drift terjadi pada setiap penerapan. Perlakukan keamanan sebagai sebuah lingkaran, bukan daftar periksa yang Anda selesaikan.

Verifikasi domain produksi Anda

Dashboard โ†’ Domains โ†’ tambahkan domain produk Anda โ†’ DNS TXT atau HTTP- verifikasi file (satu langkah). Setelah diverifikasi, pemindaian aktif akan tersedia dan pemindaian ulang terjadwal dapat diaktifkan.

Jadwalkan pemindaian ulang pasif

Setiap hari pada Hobby, setiap 3 jam pada Pro, setiap jam pada Unlimited. Setiap proses akan mengirimi Anda email jika ada temuan baru yang muncul, dan mengaktifkan webhook scan.completed jika Anda sudah berlangganan.

bash
# 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"}'

Aktifkan API- pemindaian aktif (opsional)

Jika Anda ingin pemeriksaan aktif otomatis (SQLi / XSS / IDOR berjalan / dll.), aktifkan per domain di Dasbor โ†’ Domain โ†’ API aktif. Otorisasi tahan lama, masa berlakunya 90 hari, dan dapat langsung dibatalkan. Sandingkan dengan webhook scan.active_api.first_used sehingga pemindaian aktif otomatis pertama setelah pengaktifan mencapai peringatan Anda.

Masukkan temuan ke dalam alur kerja AI Anda

Mint an API token at Account โ†’ API tokens, then configure the MCP server (/docs/mcp) in Claude Desktop / Cursor / Continue. Ask your agent: "Run a scan on staging and show me the highest-severity findings." The agent calls FixVibe, fetches the report, and renders categorized remediation guidance so code/config fixes become prompts and DNS/provider/manual fixes become operator steps.

Deteksi ancaman langsung (Unlimited)

Perbedaan log transparansi sertifikat memunculkan sertifikat TLS baru yang diterbitkan untuk domain Anda. DNS-record diffs menangkap perubahan yang tidak sah. JS-bundle pemantauan rahasia diaktifkan saat kunci baru mencapai bundel yang dikirimkan. Umpan intelijen ancaman (Spamhaus, URLhaus) laporkan domain Anda jika terdaftar.

Pola kegagalan nyata dan perbaikannya

Lima pola dari pemindaian produksi di ribuan aplikasi yang dihasilkan AI-, masing-masing dengan perbaikan sebenarnya:

  1. Kunci peran layanan dalam komponen klien

    Symptom: baas.supabase-service-key temuan pada produksi URL. Cause: a Cursor pelengkapan otomatis ditempelkan createClient(URL, SERVICE_ROLE_KEY) ke dalam komponen React. Fix: pindahkan klien layanan ke src/lib/supabase/service.ts dengan import 'server-only' di atas; membuat src/lib/supabase/client.ts paralel menggunakan kunci segera untuk penggunaan sisi klien; putar kunci peran layanan melalui Supabase Studio.

  2. Aturan Firestore dibiarkan dalam mode uji coba

    Symptom: baas.firebase-rules temuan dengan tingkat keparahan tinggi. Cause: aturan yang dihasilkan dibaca allow read, write: if request.time < timestamp.date(2026, 6, 1); โ€” "izinkan semua" yang dibatasi waktu. Fix: mencakup setiap aturan ke pengguna yang diautentikasi โ€” match /users/{userId}/posts/{postId} { allow read, write: if request.auth.uid == userId; } โ€” dan menerapkan ulang firebase deploy --only firestore:rules.

  3. Permisif CORS bertahan hingga produksi

    Symptom: active.cors tingkat keparahan tinggi. Cause: menghasilkan middleware Ekspres: app.use(cors({ origin: '*' })). Fix: izinkan asal frontend Anda: app.use(cors({ origin: ['https://your-app.com'], credentials: true })). Untuk rute Next.js API, tetapkan Access-Control-Allow-Origin secara eksplisit dalam respons.

  4. RLS diaktifkan tetapi tidak dipaksa

    Symptom: aktif baas.supabase-rls melaporkan peran segera dapat menulis ke tabel publik meskipun RLS diaktifkan di dasbor. Cause: ENABLE tanpa FORCE membuat pemilik tabel dikecualikan โ€” dan migrasi dijalankan sebagai pemilik. Fix: tambahkan alter table public.items force row level security; ke migrasi. Terapkan kembali.

  5. ID yang tidak dapat ditandatangani IDOR-walkable

    Symptom: active.idor-walking melaporkan bahwa pengguna segera dapat membaca /api/items/1, /api/items/2, ... di seluruh penyewa. Cause: API handler memercayai parameter jalur dan menanyakan Postgres tanpa predikat kepemilikan. Fix: tambahkan .eq('user_id', user.id) pada setiap kueri baca, atau pindah ke URL/UUID bertanda tangan yang tercakup dalam /api/users/[uid]/items/[id].

Lingkaran keamanan kode getaran

Tujuannya bukanlah keamanan yang sempurna; ini menghilangkan hal-hal yang selalu terlewatkan oleh alat AI sehingga Anda dapat terus melakukan pengiriman dengan cepat.

  1. Generate fast โ€” gunakan Cursor, Claude Code, Lovable, Bolt. Itulah intinya.
  2. Audit immediately โ€” jalankan set grep di atas, periksa RLS, verifikasi CSP, tinjau batas autentikasi.
  3. Harden at deploy โ€” middleware, pemisahan lingkungan, CSP nonce, HSTS, verifikasi autentikasi khusus server.
  4. Monitor โ€” FixVibe pasif harian, aktif mingguan pada domain terverifikasi, webhook ke Slack, deteksi ancaman di Unlimited.
  5. 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.

Langkah selanjutnya

Untuk latar belakang konseptual tentang DAST vs SAST dan mengapa aplikasi yang dihasilkan AI- memerlukan pemindaiannya sendiri, baca AI-generated code security scanning. Untuk referensi cepat audit pra-pengiriman, lihat vibe coding security checklist.

// scan your app

Cukup membaca. Saatnya temukan celah di aplikasimu.

Kunjungi URL โ€” FixVibe menjalankan setiap pemeriksaan pasif dari panduan ini ditambah 200+ pemeriksaan lainnya dalam waktu kurang dari satu menit. Free, tanpa instalasi, tanpa kartu.

  • Free tingkat โ€” 3 pemindaian / bulan, tanpa kartu.
  • Pemindaian pasif terhadap URL apa pun โ€” tidak memerlukan verifikasi domain.
  • Disetel untuk Cursor, Claude Code, Lovable, Bolt, v0, Replit.
  • Coding-agent prompts for code/config findings, plus operator steps for DNS/provider fixes.
Cara mengamankan aplikasi yang dibangun dengan alat coding AI โ€” Docs ยท FixVibe