Ketika sebuah website terkena Cross-Site Scripting atau XSS, masalahnya bukan hanya pada data input yang lolos. Browser juga bisa saja menjalankan script dari sumber yang seharusnya tidak dipercaya. Di sinilah Content Security Policy atau CSP berguna: sebuah aturan dari server yang memberi tahu browser resource apa yang boleh dimuat dan dijalankan.
CSP bukan pengganti validasi input, sanitasi, atau output encoding. Namun, ia dapat menjadi lapisan pertahanan kedua. Jika ada celah yang memungkinkan script asing masuk ke halaman, kebijakan CSP yang ketat dapat membatasi script tersebut agar tidak mudah berjalan.
Apa sebenarnya yang dilakukan CSP?
Bayangkan website sebagai gedung dengan banyak pintu: pintu untuk JavaScript, gambar, font, koneksi API, iframe, dan pengiriman form. Tanpa aturan, browser cenderung mengikuti instruksi yang tertanam di halaman. CSP berfungsi seperti daftar akses yang mengatakan, “Untuk jenis resource ini, hanya sumber berikut yang boleh digunakan.”
Aturan CSP biasanya dikirim melalui HTTP response header seperti ini:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'self';Contoh tersebut secara umum berarti resource hanya boleh berasal dari domain sendiri, script hanya boleh dimuat dari domain sendiri, plugin lama seperti object tidak boleh digunakan, dan halaman hanya boleh ditampilkan dalam frame dari situs yang sama.
Browser modern mendukung CSP secara luas. Meski demikian, hasil akhirnya tetap bergantung pada struktur website, browser pengguna, serta layanan pihak ketiga yang dipakai.
Bagian penting dalam sebuah kebijakan CSP
default-src sebagai aturan dasar
default-src menjadi aturan cadangan untuk jenis resource yang belum memiliki aturan khusus. Nilai 'self' berarti browser hanya mempercayai origin yang sama, yaitu kombinasi protokol, domain, dan port yang sama.
Untuk website sederhana, kebijakan awal berikut bisa menjadi titik diskusi:
Content-Security-Policy: default-src 'self';Namun, jangan langsung menganggap aturan tersebut cocok untuk semua website. WordPress, toko online, atau aplikasi yang memakai CDN, Google Fonts, payment gateway, analytics, dan layanan chat biasanya memerlukan daftar sumber tambahan.
script-src untuk membatasi JavaScript
Bagian ini mengatur dari mana JavaScript boleh dimuat. Salah satu tujuan pentingnya adalah mencegah browser mengeksekusi script inline atau script dari domain asing.
script-src 'self';Aturan ini bisa membuat kode seperti <script>... dan atribut event seperti onclick tidak berjalan. Dari sisi keamanan, ini baik. Dari sisi kompatibilitas, website lama mungkin langsung menampilkan error karena masih bergantung pada kode inline.
Hindari menambahkan 'unsafe-inline' hanya karena ada bagian halaman yang rusak. Nilai tersebut memang dapat memulihkan kompatibilitas, tetapi juga mengurangi manfaat perlindungan terhadap XSS. Lebih baik pindahkan JavaScript inline ke file terpisah atau gunakan nonce dan hash jika arsitektur aplikasi memang membutuhkannya.
frame-ancestors untuk mencegah clickjacking
Clickjacking terjadi ketika halaman Anda ditampilkan di dalam frame milik situs lain lalu pengguna diarahkan untuk menekan sesuatu tanpa menyadarinya. Untuk melarang halaman ditampilkan dalam frame, gunakan:
frame-ancestors 'none';Jika halaman memang perlu ditampilkan oleh situs sendiri, gunakan frame-ancestors 'self'. Jika ada partner resmi, masukkan domain yang benar-benar diperlukan, bukan wildcard yang terlalu luas.
form-action untuk membatasi tujuan form
CSP juga dapat membatasi lokasi tujuan pengiriman form:
form-action 'self';Ini membantu mencegah form palsu yang disisipkan ke halaman lalu mengirim kredensial atau data pengguna ke domain asing. Untuk website yang memakai payment gateway, domain tujuan resmi perlu ditambahkan secara eksplisit.
Jangan langsung mengaktifkan mode pemblokiran
Kesalahan umum saat menerapkan CSP adalah membuat aturan terlalu ketat lalu memasangnya langsung di website produksi. Akibatnya, tombol tertentu tidak bekerja, font hilang, formulir pembayaran gagal, atau analytics berhenti mengirim data.
Gunakan Content-Security-Policy-Report-Only terlebih dahulu. Mode ini tidak memblokir resource, tetapi browser mencatat pelanggaran sehingga Anda dapat melihat bagian mana yang belum sesuai.
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'self';Uji halaman penting seperti login, checkout, dashboard admin, formulir kontak, dan halaman yang memakai editor visual. Buka Developer Tools di browser, periksa pesan pelanggaran CSP, lalu catat sumber yang memang dibutuhkan.
Bedakan antara resource resmi dan resource yang hanya kebetulan muncul. Jika ada script dari domain yang tidak dikenal, jangan buru-buru memasukkannya ke daftar izin. Cari tahu plugin atau fitur apa yang memanggilnya. Bisa jadi itu dependensi lama, script iklan, atau komponen yang sebaiknya dihapus.
Penerapan untuk WordPress dan PHP
Pada WordPress, CSP sebaiknya diterapkan setelah inventarisasi plugin dan layanan eksternal. Plugin keamanan dapat membantu menambahkan header, tetapi pemilik website tetap perlu memahami kebijakannya. Header yang terlalu umum kadang membuat fitur editor, preview, atau integrasi pembayaran gagal.
Jika menggunakan PHP tanpa framework, header dapat dikirim sebelum output HTML:
<?php
header("Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'self';");
?>Dalam praktik, konfigurasi sebaiknya dikelola di server atau middleware agar konsisten pada seluruh response. Pastikan juga tidak ada output yang dikirim sebelum fungsi header() dipanggil.
Untuk konfigurasi Nginx atau Apache, prinsipnya sama: kirim header dari server, lalu uji semua alur penting. CSP melalui meta tag bisa menjadi pilihan ketika header server tidak dapat diubah, tetapi tidak mendukung seluruh kemampuan CSP. Untuk perlindungan yang lebih lengkap, response header tetap lebih disarankan.
Yang bisa dilakukan sekarang
- Inventarisasi JavaScript, font, gambar, iframe, API, dan layanan pihak ketiga yang dipakai website.
- Buat kebijakan awal yang membatasi resource ke
'self'dan menonaktifkan object denganobject-src 'none'. - Pasang kebijakan dalam mode
Report-Onlydi staging atau produksi secara terpantau. - Periksa pelanggaran pada halaman login, formulir, checkout, dan dashboard.
- Hapus dependensi yang tidak diperlukan sebelum menambahkan domain baru ke daftar izin.
- Setelah stabil, ubah ke header
Content-Security-Policydan pantau error setelah peluncuran.
Intinya
CSP bukan tombol ajaib yang membuat website aman dari semua serangan. Validasi input, sanitasi output, pengelolaan session, pembaruan dependensi, dan pembatasan hak akses tetap menjadi fondasi utama.
Namun, CSP membuat browser tidak sekadar menjadi penampil halaman. Browser juga ikut menegakkan batasan tentang script dan resource apa yang boleh berjalan. Mulailah secara bertahap, gunakan mode Report-Only, dan anggap setiap domain yang dimasukkan ke daftar izin sebagai keputusan keamanan—bukan sekadar solusi agar error menghilang.
Sumber & bacaan lebih lanjut
- Content Security Policy Cheat Sheet - OWASP
- Content Security Policy - HTTP - MDN Web Docs
- Content Security Policy - MDN Web Docs
- Content Security Policy implementation - MDN Web Docs
– Rio Yotto @rioyotto
