Belajar Fullstack Developer - Security Fullstack
Episode 16 of 28

Belajar Fullstack Developer - Security Fullstack

Mengamankan aplikasi fullstack dengan lensa OWASP: menutup XSS dan SQL injection, memahami proteksi CSRF pada server actions, menerapkan Content Security Policy, dan mengelola secrets dengan aman.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Keamanan bukan fitur yang "ditambahkan terakhir" — ia adalah keputusan desain yang merembes ke setiap lapisan. Episode ini membahas security fullstack dengan kerangka OWASP Top 10 sebagai peta: XSS, CSRF, injection, dan pengelolaan secrets. Kalian tidak perlu menjadi pentester; kalian perlu memahami pola serangan agar tidak membangun celah.

Mengapa topik ini khusus fullstack? Karena celah keamanan lahir di persimpangan lapisan: input dari browser masuk ke server, query menggabungkan string, atau file yang diunggah disajikan sebagai HTML. Memahami kedua sisi adalah senjata terbaik kalian.

OWASP Top 10: Kenali Musuh

Lima dari sepuluh kerentanan paling umum yang paling relevan untuk aplikasi fullstack:

PeringkatKerentananInti Masalah
A01Broken Access ControlUser bisa akses data yang bukan miliknya
A02Cryptographic FailuresData sensitif tidak dienkripsi
A03InjectionInput user dieksekusi sebagai kode
A05Security MisconfigurationDefault yang tidak aman
A07XSSScript jahat dieksekusi di browser korban

Fokus episode ini: Injection (A03) dan XSS (A07) — keduanya paling sering muncul dan paling bisa dicegah dengan praktik rutin.

XSS: Script Jahat di Browser Korban

XSS terjadi saat input user dirender sebagai kode. Tiga jenisnya:

JenisCara Kerja
ReflectedPayload di URL, dirender di response
StoredPayload tersimpan di database, dirender untuk semua
DOMPayload dijalankan oleh JavaScript client

Pertahanan Utama: Escaping

React/Next.js secara default melakukan escaping — teks yang kalian render sebagai string tidak akan dieksekusi:

Escaping otomatis oleh React
const userInput = "<script>alert(1)</script>"
return <p>{userInput}</p> // aman: dirender sebagai teks

Celah muncul saat kalian sengaja mematikan proteksi. Dua pelanggaran paling umum:

  • dangerouslySetInnerHTML — render HTML mentah. Hindari; jika terpaksa, sanitasi dulu dengan library (DOMPurify).
  • Markdown dari user yang di-render tanpa sanitasi — vektor XSS populer.
Contoh yang harus dihindari
// JANGAN — HTML mentah dari user
<div dangerouslySetInnerHTML={{ __html: userContent }} />

Important

Aturan XSS yang paling mudah diingat: semua input tidak dipercaya, semua output di-escape. Saat harus me-render HTML buatan user (konten Markdown, rich text), jalankan melalui sanitizer yang matang (DOMPurify di client, sanitize-html di server) — dan pertimbangkan bahwa "membersihkan HTML" lebih sulit dari kelihatannya.

SQL Injection: Input Jadi Query

Injection klasik: string input digabung langsung ke query. Contoh buruk:

Pola rentan injection
// JANGAN — concatenation SQL mentah
const sql = `SELECT * FROM users WHERE email = '${email}'`

Untungnya Prisma selalu memakai parameterized query — input tidak pernah dicampur langsung ke SQL. Dengan ORM, risiko ini hampir hilang otomatis. Yang tersisa: query mentah ($queryRaw). Jika wajib memakainya, jangan gabungkan variabel:

Query mentah yang aman
const rows = await prisma.$queryRaw`
  SELECT * FROM users WHERE email = ${email}
`

Template literal Prisma menangani binding dengan aman — tidak seperti menggabungkan string manual.

CSRF: Memanfaatkan Session yang Sah

CSRF: penyerang menipu browser korban (yang sudah login) untuk mengirim request jahat. next-auth dan server actions Next.js menangani ini dengan double-submit token secara bawaan — form server action sudah terlindungi tanpa kerja ekstra.

Masalah muncul jika kalian membangun API publik (episode 5) yang mengubah data dan dipanggil dari browser dengan cookie session. Untuk itu, periksa Origin/Referer pada request mutasi:

Cek Origin di route handler
export async function POST(request: Request) {
  const origin = request.headers.get("origin")
  if (origin !== process.env.APP_URL) {
    return Response.json({ error: "Forbidden" }, { status: 403 })
  }
  // proses mutasi...
}

Content Security Policy (CSP)

CSP adalah aturan yang memberi tahu browser sumber apa saja yang boleh dimuat. Ini lapisan pertahanan kedua saat XSS lolos — script dari domain tak dikenal diblokir:

CSP via Next.js headers
export default function NextConfig() {
  return {
    headers: async () => [
      {
        source: "/(.*)",
        headers: [
          {
            key: "Content-Security-Policy",
            value: [
              "default-src 'self'",
              "script-src 'self'",
              "style-src 'self' 'unsafe-inline'",
              "img-src 'self' data: https:",
              "connect-src 'self'",
            ].join("; "),
          },
        ],
      },
    ],
  }
}

Mulai ketat lalu longgarkan seperlunya (karena Next.js butuh 'unsafe-inline' untuk style, dan inline script tertentu). Log pelanggaran CSP di awal — jangan langsung blokir.

Secrets: Jangan Sampai Bocor

Sebagian besar "kebocoran API key" adalah kesalahan sederhana yang bisa dicegah:

  1. Tidak pernah hardcode secret di source code.
  2. Tidak pernah commit .env* (sudah di .gitignore repo ini).
  3. Jangan pakai prefiks NEXT_PUBLIC_ untuk secret server — prefiks itu mengirim nilai ke browser!
  4. Rotasi secret yang pernah ter-expose — anggap bocor = diganti.
Pemisahan env yang benar
# .env.local (hanya server)
DATABASE_URL="postgresql://..."
STORAGE_SECRET_KEY="rahasia-server"
 
# NEXT_PUBLIC_ hanya untuk nilai yang BOLEH dilihat browser
NEXT_PUBLIC_APP_URL="https://app.example.com"

Warning

Aturan paling murah di dunia keamanan: apa pun yang diawali NEXT_PUBLIC_ akan dikirim ke browser. Jika suatu secret terlihat di DevTools, ia sudah tidak bisa dianggap rahasia. Audit rutin: grep NEXT_PUBLIC_ di repo kalian dan pastikan tidak ada yang sensitif.

Praktik: Audit Keamanan Aplikasi

Jalankan checklist berikut di aplikasi catatan:

  1. Injection: cek semua $queryRaw — apakah ada variabel tercampur ke string SQL?
  2. XSS: grep dangerouslySetInnerHTML — hapus atau sanitasi.
  3. CSRF: pastikan route handler mutasi memeriksa Origin.
  4. Secrets: grep NEXT_PUBLIC_ — jangan ada secret di dalamnya.
  5. CSP: pasang header CSP minimal dan uji tidak ada yang rusak.
Audit cepat
rg "dangerouslySetInnerHTML|queryRaw|NEXT_PUBLIC_.*KEY" src/

Penutup

Inti yang harus dibawa pulang:

  • OWASP Top 10 adalah peta; kenali pola serangan, bukan hafal daftar.
  • XSS dicegah dengan escaping (bawaan React) + sanitasi HTML buatan user.
  • SQL injection dicegah oleh ORM parameterized; jangan campur string di $queryRaw.
  • CSRF ditangani server actions; route handler API wajib cek Origin.
  • CSP sebagai lapisan kedua; secrets tidak pernah hardcode dan tidak pernah NEXT_PUBLIC_.

Di episode 17 selanjutnya kita membahas deployment & CI/CD — environments, pipeline, dan deploy produksi — agar aplikasi yang sudah kalian bangun bisa sampai ke tangan pengguna dengan aman. Sampai jumpa di episode 17!

Belajar Fullstack Developer - Security Fullstack | Belajar Fullstack