Cara Mencegah Prompt Injection untuk Developer
Prompt injection lahir dari satu keputusan desain: model bahasa menerima instruksi dan data lewat kanal yang sama. Tidak ada pembatas sintaksis seperti tanda kutip pada SQL. Kalimat "abaikan semua instruksi sebelumnya" yang terselip di sebuah dokumen PDF punya jalur masuk yang sama dengan system prompt Anda, hanya dibedakan oleh posisi dan bobot statistik.
Karena itu, banyak saran mitigasi yang beredar sebenarnya kosmetik: menyuruh model "jangan menuruti instruksi di dalam teks pengguna", menambah kalimat tegas di system prompt, atau memasang penanda seperti ### END OF DATA ###. Semua itu menaikkan sedikit biaya serangan, tapi bukan batas keamanan. Penyerang bisa mengganti bahasa, memakai encoding, menyisipkan perintah di komentar HTML, atau menaruh instruksi di metadata file yang tidak pernah Anda baca.
Cara mencegah prompt injection yang bekerja ada di level arsitektur, bukan di level kalimat. Prinsipnya satu: jangan beri model kekuatan yang tidak bisa Anda batasi dari luar model. Perlakukan keluaran model sebagai masukan tidak tepercaya, setara dengan parameter HTTP dari pengguna asing.
Pisahkan Data dan Instruksi Secara Struktural
Pemisahan peran pesan (system, user, tool) membantu, tetapi bukan kontrol keamanan. Yang lebih menentukan adalah bentuk data yang Anda kirim ke model.
- Kirim konteks sebagai field terstruktur yang divalidasi (JSON dengan skema), bukan hasil konkatenasi string ke dalam template prompt.
- Jangan pernah menyusun system prompt dari input pengguna. Jika perlu personalisasi, simpan sebagai data terpisah di dalam pesan pengguna, bukan di instruksi sistem.
- Untuk dokumen dan hasil RAG, bungkus konten sebagai blok berlabel "konten yang harus dianalisis", batasi panjangnya, dan potong bagian yang tidak relevan.
- Tandai asal setiap potongan konteks. Model yang tahu sebuah teks berasal dari unggahan pengguna lebih mudah diarahkan untuk tidak mengeksekusinya sebagai perintah — meski ini tetap lapisan tambahan, bukan jaminan.
Perlu diingat: semua teknik di atas tetap bisa ditembus. Fungsinya mengurangi ruang gerak penyerang, bukan menutup rapat.
Batasi Izin Tool: Allowlist, Bukan Blocklist
Di sinilah sebagian besar insiden nyata terjadi. Model yang bisa memanggil tool generik seperti "jalankan query SQL" atau "ambil URL apa pun" pada dasarnya memberi penyerang akses ke infrastruktur Anda lewat bahasa alami. Beberapa aturan yang layak dipegang:
- Tidak ada tool serba bisa. Pecah menjadi aksi sempit:
baca_tiket(id), bukanquery_database(sql). - Parameter tertutup. Setiap parameter punya tipe, rentang, dan pola yang diperiksa sebelum eksekusi. ID tiket harus cocok dengan format dan harus milik pengguna yang sedang memanggil.
- Read-only secara default. Aksi tulis berada di jalur terpisah dengan otorisasi tambahan.
- Konfirmasi manusia untuk aksi destruktif — kirim email massal, hapus data, transfer, ubah izin, atau panggilan ke sistem pembayaran.
- Hasil tool adalah data, bukan kebijakan. Keluaran tool tidak boleh mengubah allowlist, menambah tool baru, atau memperluas izin sesi.
Poin terakhir berkaitan erat dengan excessive agency: agent yang bisa memilih sendiri tool dan parameternya memperbesar dampak satu injeksi yang berhasil. Semakin sempit ruang pilihan, semakin kecil kerusakan maksimumnya.
Validasi Keluaran Sebelum Disentuh Sistem Lain
Banyak orang lupa bahwa keluaran model juga titik serang. Model bisa diminta menghasilkan URL, HTML, atau potongan kode yang kemudian diproses aplikasi Anda tanpa pemeriksaan.
- Parse keluaran ke skema ketat. Jika gagal validasi, tolak — jangan "perbaiki seadanya".
- Jangan render HTML atau Markdown mentah. Gambar Markdown dan tautan bisa dipakai untuk mengirim data keluar lewat query string.
- Jangan pernah meneruskan keluaran ke
eval, shell, atau query tanpa parameterisasi. - Periksa URL hasil model terhadap allowlist domain sebelum diambil atau ditampilkan.
- Batasi panjang keluaran dan jumlah iterasi agar tidak terjadi loop boros.
AISG memindai aplikasi web dari sisi luar dengan sensor yang berjalan lokal di mesin Anda. Untuk aplikasi berbasis LLM, pemindaian otomatis hanya memberi indikasi permukaan serangan — bukan bukti bahwa prompt injection berhasil dieksploitasi. Temuan tetap perlu divalidasi manusia. Ada pemindaian URL gratis tanpa akun di /#free-scan jika ingin melihat tampilan awal.
Contoh Pola Tool yang Lebih Aman
Bandingkan dua desain berikut. Yang pertama memberi model kendali penuh; yang kedua memindahkan keputusan ke kode Anda.
- Buruk:
jalankan_perintah(cmd: string)— model bisa mengirim apa saja, termasuk perintah yang membaca kredensial. - Lebih baik:
baca_log(service: enum, baris: int)—servicedivalidasi terhadap daftar tetap,barisdibatasi 1–200, dan path file dibangun di server, bukan dari model. - Buruk:
kirim_email(tujuan: string, isi: string)— satu injeksi cukup untuk mengirim data ke alamat penyerang. - Lebih baik:
kirim_notifikasi(template_id: enum, penerima_id: int)— template tetap, penerima diambil dari basis data berdasarkan ID, dan pengiriman ke domain luar diblokir.
Untuk tool pembacaan file, resolusi path di server, lalu pastikan hasil resolusi tetap berada di dalam direktori yang diizinkan. Jangan mengandalkan pemeriksaan string seperti menolak .. — gunakan kanonisasi path dan bandingkan dengan akar direktori.
Uji dengan Input Jahat, Lalu Ulangi
Mitigasi tanpa pengujian cepat basi. Setiap kali Anda mengubah prompt, menambah tool, atau mengganti model, jalankan ulang kumpulan uji serangan.
- Siapkan korpus serangan kecil: instruksi untuk mencetak system prompt, permintaan mengirim data ke URL luar, perintah tersembunyi dalam komentar HTML, teks warna putih, karakter bidi Unicode, dan instruksi dalam bahasa lain.
- Tanam canary token di system prompt. Jika token itu muncul di keluaran atau di log keluar, ada kebocoran.
- Catat setiap pemanggilan tool beserta argumen dan alasan yang diberikan model. Pola anomali biasanya terlihat di sini lebih dulu.
- Uji juga jalur gagal: apa yang terjadi jika validasi skema menolak keluaran model? Aplikasi harus berhenti dengan aman, bukan jatuh ke perilaku default yang permisif.
Perlu ditegaskan: rangkaian uji ini mengukur ketahanan terhadap serangan yang Anda pikirkan, bukan seluruh kemungkinan. Hasilnya indikasi, bukan sertifikat.
Kesimpulan
Cara mencegah prompt injection yang bertahan adalah batas izin tool bukan kalimat larangan di prompt. Pindahkan keputusan keamanan keluar dari model: skema data yang ketat, tool sempit dengan parameter tervalidasi, aksi berisiko lewat konfirmasi manusia, dan keluaran model yang tidak pernah dipercaya mentah-mentah. Kalimat "jangan" di system prompt boleh tetap ada, tapi jangan pernah menjadi satu-satunya lapisan.
Mulai dari yang paling murah: daftar tool yang Anda ekspos, parameter apa yang bisa dikendalikan model, dan data apa yang bisa keluar jika satu injeksi berhasil. Setelah itu baru poles prompt. Keamanan aplikasi LLM lebih banyak soal desain izin daripada soal kata-kata.