Apa itu Content Security Policy?
CSP adalah HTTP header yang memberi tahu browser sumber mana yang boleh memuat resource (script, style, image, dll.). CSP adalah pertahanan kuat terhadap XSS karena bahkan jika penyerang berhasil menyisipkan script, browser akan menolak menjalankannya jika sumbernya tidak diizinkan.
Bagaimana CSP Bekerja
// HTTP Response Header
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
// Artinya:
// - Secara default, hanya izinkan resource dari origin sendiri
// - Script hanya boleh dari origin sendiri dan cdn.example.com
// - Inline script DIBLOKIR (kecuali pakai nonce/hash)
Directive Utama CSP
- default-src — Fallback untuk semua tipe resource
- script-src — Sumber JavaScript yang diizinkan
- style-src — Sumber CSS yang diizinkan
- img-src — Sumber gambar yang diizinkan
- connect-src — URL yang boleh dihubungi (fetch, XHR, WebSocket)
- font-src — Sumber font yang diizinkan
- frame-src — Sumber iframe yang diizinkan
- frame-ancestors — Siapa yang boleh meng-embed halaman ini
Menggunakan Nonce untuk Inline Script
// Server generate nonce unik per request
Content-Security-Policy: script-src 'nonce-abc123xyz'
// HTML — script dengan nonce yang sesuai DIIZINKAN
<script nonce="abc123xyz">
console.log("Script ini diizinkan");
</script>
// Script tanpa nonce atau nonce salah DIBLOKIR
<script>
console.log("Script ini diblokir!");
</script>
CSP Report-Only Mode
Uji CSP tanpa memblokir apapun — hanya kirim laporan pelanggaran:
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
// Browser akan melaporkan pelanggaran ke /csp-report tanpa memblokir
// Berguna untuk testing sebelum enforce
Contoh CSP yang Realistis
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{random}' https://cdn.jsdelivr.net;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src 'self' data: https://images.example.com;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self'
Tips Implementasi
- Mulai dengan Report-Only untuk melihat apa yang akan diblokir
- Gunakan nonce daripada
unsafe-inlineuntuk script - Hindari unsafe-eval — ini membuka pintu untuk XSS
- Set frame-ancestors untuk mencegah clickjacking
- Gunakan strict-dynamic jika butuh load script secara dinamis