Nonce Content Security Policy Mengendalikan Eksekusi Script
Content Security Policy dapat mengubah eksekusi script dari aturan lokasi yang luas menjadi keputusan eksplisit untuk setiap respons. Alih-alih mempercayai setiap script yang disajikan dari host yang diizinkan, server menempatkan nonce baru di dalam policy lalu menyalin nilai tersebut hanya ke elemen script yang memang hendak diotorisasi.
Content-Security-Policy: script-src 'nonce-r4nd0mBase64Value'<script nonce="r4nd0mBase64Value" src="/assets/app.js"></script>Elemen script tanpa nonce yang cocok tidak mendapat otorisasi dari directive tersebut. Markup hasil injeksi menjadi lebih terbatas bagi penyerang ketika jalur injeksi tidak dapat memperoleh nonce yang valid.
Nonce merupakan kapabilitas untuk satu respons
Nilai nonce dibuat server untuk sebuah respons HTTP. Nilainya harus sulit diprediksi dan tidak boleh dipakai ulang sebagai konstanta aplikasi. Header respons dan elemen script yang diotorisasi membawa nilai yang sama.
Desain ini penting karena nilai tetap pada akhirnya hanya menjadi bagian biasa dari markup publik. Saat penyerang dapat memprediksi atau memakainya kembali, nilai tersebut tidak lagi membedakan elemen script yang diotorisasi server dari elemen hasil injeksi.
Pembuatan nonce karena itu berada pada pemrosesan request atau respons dengan sumber acak yang aman secara kriptografis. Nilai yang dihasilkan kemudian dapat diteruskan ke template renderer dan pembentuk header CSP untuk respons tersebut.
request
-> buat nonce baru
-> susun header CSP
-> render tag script resmi dengan nonce yang sama
-> kirim responsNonce bukan rahasia setelah respons tiba di browser. Peran keamanannya bergantung pada ketidakmampuan pihak lain memprediksi nilai sebelum respons dibuat serta pada pencegahan jalur injeksi agar tidak dapat menempatkan nilai valid itu pada markup script milik penyerang.
Allowlist host dan nonce menyatakan kepercayaan yang berbeda
Policy berbasis host seperti script-src 'self' mempercayai resource script berdasarkan origin. Pendekatan itu berguna, tetapi setiap resource script yang dapat dijangkau dari origin tepercaya dapat ikut masuk ke batas policy.
Policy berbasis nonce mengotorisasi elemen script individual yang dikeluarkan aplikasi. Browser memeriksa nonce pada elemen terhadap nonce source di dalam policy.
Perbedaan ini relevan ketika sebuah origin menyajikan file yang dikendalikan pengguna, endpoint lama, respons menyerupai JSONP, atau konten lain yang tidak semestinya otomatis mendapat kepercayaan sebagai script. Nonce tidak memperbaiki sistem tersebut, tetapi dapat mempersempit aturan eksekusi script.
Inline script dapat diotorisasi tanpa unsafe-inline
CSP memblokir inline script biasa ketika script-src yang ketat berlaku. Nonce yang cocok menyediakan pengecualian yang terarah.
<script nonce="r4nd0mBase64Value">
window.appConfig = { apiBase: "/api" };
</script>Cara ini jauh lebih sempit dibanding menambahkan 'unsafe-inline', yang mengizinkan inline script secara luas pada directive tersebut. Aplikasi yang memerlukan blok bootstrap kecil dapat mengotorisasi elemen tertentu saja.
Atribut event handler seperti onclick tidak berubah menjadi script yang diotorisasi nonce hanya karena elemen di dekatnya memiliki nonce. Memindahkan perilaku executable ke elemen script eksplisit juga membuat batas otorisasi lebih mudah diaudit.
strict-dynamic dapat meneruskan kepercayaan dari script resmi
Nonce dapat dipasangkan dengan 'strict-dynamic':
Content-Security-Policy: script-src 'nonce-r4nd0mBase64Value' 'strict-dynamic'Pada browser yang mendukungnya, 'strict-dynamic' memungkinkan kepercayaan yang diberikan kepada script dengan nonce atau hash diteruskan ke script yang dimuat secara programatis oleh script tepercaya tersebut. Pola ini berguna bagi aplikasi yang memakai script bootstrap untuk memuat modul atau bundle tambahan.
Efeknya berbeda dari sekadar menambah hostname. Jalur kepercayaan dimulai dari script yang secara eksplisit diotorisasi, bukan dari setiap resource pada origin script yang tercantum.
Kebutuhan kompatibilitas tetap perlu diperhitungkan. Policy produksi dapat memuat source expression tambahan untuk klien lama, tetapi expression tersebut sebaiknya dipilih berdasarkan matriks dukungan aplikasi, bukan disalin dari contoh CSP generik.
Nonce tidak membersihkan data yang dikendalikan penyerang
CSP adalah lapisan enforcement browser, bukan input sanitizer atau output encoder. Escaping yang sesuai konteks tetap diperlukan saat data tidak tepercaya masuk ke HTML, atribut, URL, CSS, atau JavaScript.
Pola berbahaya dapat muncul ketika nonce ditempatkan pada elemen script yang body-nya berisi teks dari penyerang tanpa serialisasi aman:
<script nonce="...">
const profile = /* serialisasi yang dikendalikan penyerang */;
</script>Browser melihat elemen script yang telah diotorisasi. CSP tidak memeriksa aliran data JavaScript lalu menentukan apakah isi script aman. Batas tersebut tetap menjadi tanggung jawab aplikasi.
Prinsip yang sama berlaku pada injeksi berbasis DOM. Jika JavaScript tepercaya mengubah string tidak tepercaya menjadi script executable atau HTML berbahaya, nonce bukan pengganti DOM API yang aman dan penanganan data yang ketat.
Template harus membatasi nonce pada elemen resmi
Lapisan templating sering memerlukan akses ke nonce agar dapat merender tag script yang diotorisasi. Hal itu tidak berarti nonce perlu tersedia sebagai variabel template serbaguna bagi fragmen yang dikendalikan pengguna.
Jalur rendering sebaiknya membuat keputusan otorisasi terlihat jelas. Helper bersama dapat mengeluarkan script aplikasi yang sudah dikenal beserta nonce, sedangkan konten tidak tepercaya tetap diperlakukan sebagai data.
Pemisahan ini juga mengurangi penyebaran yang tidak disengaja. Komponen yang dapat menyalin atribut arbitrer dari input pengguna ke elemen <script> dapat merusak batas yang diharapkan jika komponen tersebut juga dapat menerima nonce valid.
Caching memerlukan penanganan khusus
Nonce per respons berinteraksi dengan caching HTML. Jika cache menyimpan halaman yang sudah dirender lengkap dengan nonce dan header CSP, pemutaran ulang respons lengkap tersebut juga memutar ulang nonce.
Perilaku itu bertentangan dengan tujuan menghasilkan nilai baru pada setiap respons. Sistem yang melakukan cache HTML memerlukan desain yang menjaga nilai header dan markup tetap sinkron sambil tetap menghasilkan nonce baru, atau memakai strategi CSP lain seperti hash jika model kontennya sesuai.
Mengubah header saja atau markup saja juga keliru: kedua nilai harus cocok agar script yang diotorisasi dapat dieksekusi.
Reporting membantu menemukan kerusakan policy
Policy ketat dapat memblokir script yang masih dibutuhkan aplikasi. Mekanisme reporting CSP dapat memberikan bukti tentang pelanggaran selama rollout, sedangkan Content-Security-Policy-Report-Only dapat mengevaluasi kandidat policy tanpa melakukan enforcement.
Mode report-only adalah alat bantu deployment, bukan kontrol akhir. Setelah policy sesuai dengan perilaku aplikasi yang dimaksud, enforcement harus berasal dari header Content-Security-Policy.
Report juga dapat memuat URL atau konteks operasional lain. Endpoint pengumpulan dan aturan retensi sebaiknya memperlakukan data tersebut sebagai telemetri keamanan, bukan sekadar output debug.
Batasnya adalah otorisasi script yang eksplisit
CSP berbasis nonce paling efektif ketika aplikasi dapat menentukan elemen script yang memang hendak dieksekusi, menghasilkan nonce baru untuk setiap respons, dan membatasi nilai tersebut pada elemen-elemen itu.
Kontrol ini tidak menggantikan output encoding, konstruksi DOM yang aman, kontrol dependency, atau otorisasi server. Nilainya lebih sempit dan konkret: markup script hasil injeksi tidak mendapat eksekusi hanya karena muncul di dokumen. Eksekusi memerlukan otorisasi yang ditempelkan server pada respons.