Nonce CSP Mengikat Eksekusi Script ke Setiap Response
Content Security Policy dapat membatasi script yang dieksekusi browser setelah menerima sebuah dokumen. Policy berbasis nonce memindahkan keputusan itu dari host allowlist yang luas: server menempatkan nilai baru yang tidak dapat diprediksi pada policy response, lalu menyalin nilai tersebut hanya ke elemen script yang memang hendak diizinkan.
Mekanisme ini memiliki batas yang jelas. Nonce tidak melakukan sanitasi HTML, tidak membuktikan bahwa sebuah script aman, dan tidak memperbaiki DOM API yang digunakan secara tidak aman. Nonce memberi browser token otorisasi untuk elemen script tertentu dalam satu response dokumen.
Policy dan elemen harus membawa nilai yang sama
Sebuah response dapat mengirim policy berikut:
Content-Security-Policy: script-src 'nonce-RANDOM_VALUE'; object-src 'none'; base-uri 'none'Dokumen kemudian menandai script yang diizinkan dengan nilai yang sama:
<script nonce="RANDOM_VALUE" src="/assets/app.js"></script>Browser membandingkan nonce source pada script-src dengan atribut nonce pada elemen. Nilai yang cocok mengizinkan script tersebut menurut policy. Elemen script yang disisipkan tanpa nilai yang cocok tidak memperoleh izin hanya karena URL-nya berasal dari origin yang sama.
Nonce merupakan data policy, bukan credential rahasia untuk mengautentikasi user. Peran keamanannya bergantung pada ketidakmampuan attacker memprediksi nilai sebelum response dibuat dan ketidakmampuan menempatkan nilai tersebut pada markup script yang dikendalikan attacker melalui jalur rendering aplikasi.
Buat nonce baru yang tidak dapat diprediksi untuk setiap response
Nonce sebaiknya dibuat secara independen untuk setiap response HTML. Penggunaan ulang satu nilai pada banyak response mengubah mekanisme otorisasi per-response menjadi token stabil yang dapat disalin ke percobaan injection berikutnya.
Server memerlukan sumber random yang kuat secara kriptografis serta encoding yang valid untuk CSP source expression dan atribut HTML. Nilai yang sama dipakai pada response header dan setiap elemen script yang sengaja diizinkan untuk dokumen tersebut.
request
|
v
buat nonce baru R
|
+--> response header: 'nonce-R'
|
+--> trusted script tag: nonce="R"Caching harus mempertahankan invariant ini. Cache yang menyimpan HTML dengan nonce lalu menyajikan dokumen hasil render yang sama berulang kali juga mengulang nonce tersebut. Aplikasi yang memakai shared cache atau edge cache memerlukan desain response yang menjaga pembuatan nonce tetap selaras dengan pengiriman dokumen.
Penyisipan nonce berada di rendering code yang tepercaya
Templating layer sebaiknya memasang nonce hanya pada elemen script yang dipilih oleh application code tepercaya. Menambahkan nonce secara buta ke setiap elemen <script> pada output hasil render dapat mengizinkan markup yang masuk melalui celah injection.
Perbedaan ini penting ketika template merender fragmen HTML yang tidak tepercaya. Renderer tidak boleh menganggap setiap node berbentuk script sebagai tepercaya hanya karena node tersebut sudah ada sebelum response akhir diserialisasi.
Hal serupa berlaku pada string interpolation di dalam inline script yang sudah diizinkan:
<script nonce="RANDOM_VALUE">
const profile = {{ unescaped_user_data }};
</script>Nonce mengizinkan elemen script. Nonce tidak membuat interpolation yang tidak aman menjadi aman. Data yang dimasukkan ke JavaScript tetap memerlukan strategi serialization sesuai konteks yang tidak memungkinkan data keluar menjadi syntax yang dapat dieksekusi.
strict-dynamic mengubah propagasi trust script
Nonce dapat digabungkan dengan CSP source expression strict-dynamic:
Content-Security-Policy: script-src 'nonce-RANDOM_VALUE' 'strict-dynamic'; object-src 'none'; base-uri 'none'Pada browser yang mendukungnya, trust yang diberikan kepada root script melalui nonce atau hash dapat diteruskan ke script yang dimuat secara dinamis oleh script tepercaya tersebut. Host source expression, scheme source expression, 'self', dan 'unsafe-inline' diabaikan untuk directive itu ketika strict-dynamic berlaku.
Pola ini berguna untuk aplikasi yang memakai bootstrap script tepercaya untuk memuat module atau bundle tambahan saat runtime. Namun, perhatian kemudian berpindah ke bootstrap code. Jika code tepercaya membuat elemen script dari URL yang dikendalikan attacker, trust yang diteruskan dapat mengizinkan load tersebut. Policy tidak memvalidasi data flow aplikasi.
Strict CSP tetap merupakan lapisan pertahanan, bukan validator input
CSP berbasis nonce lazim dipakai sebagai mitigasi XSS. Policy dapat memblokir elemen script hasil injection yang tidak memiliki otorisasi meskipun markup berbahaya mencapai dokumen.
Aplikasi tetap memerlukan output encoding sesuai konteks, konstruksi DOM yang aman, serta sanitization ketika HTML memang sengaja diterima. Kontrol tersebut bekerja pada titik berbeda dalam jalur dari data tidak tepercaya menuju code yang dapat dieksekusi.
Inline event handler dan URL javascript: tidak memperoleh izin hanya karena nonce dipasang pada elemen script lain. API yang mengevaluasi string sebagai code juga tetap dibatasi kecuali policy secara eksplisit mengizinkan capability terkait.
Policy yang menambahkan 'unsafe-inline' secara luas dapat merusak pembatasan yang dimaksud pada user agent ketika source expression tersebut efektif. Komposisi policy karena itu perlu ditinjau dengan ketelitian yang sama seperti code yang menghasilkan atribut nonce.
Report-only dapat menampilkan gangguan sebelum enforcement
Aplikasi dengan inline script lama, third-party loader, atau pembuatan script saat runtime dapat mengalami eksekusi yang diblokir ketika strict policy diaktifkan. Content-Security-Policy-Report-Only dapat dipakai untuk mengamati violation tanpa menerapkan candidate policy sebagai enforcement.
Report merupakan sinyal diagnostik, bukan bukti bahwa policy sudah lengkap. Cakupan pengujian sebaiknya mencakup route, authentication state, error page, localized template, dan jalur code yang dimuat dinamis serta menghasilkan bentuk dokumen berbeda.
Setelah enforcement aktif, telemetry tetap dapat menunjukkan policy violation yang tidak diperkirakan. Report dapat memuat detail aplikasi, sehingga pengumpulan dan retention memerlukan kontrol privasi serta akses yang setara dengan operational log lain.
Boundary-nya presisi
Nonce CSP menjawab satu pertanyaan di sisi browser: elemen script mana dalam response ini yang menerima otorisasi dari policy server. Pembuatan nilai baru menjaga otorisasi tetap terbatas pada response tersebut, sedangkan penyisipan yang disiplin pada template menjaga nonce tetap melekat pada script yang memang dimaksudkan.
Batas tersebut bernilai karena cakupannya terbatas. Nonce tidak menjamin perilaku script dan tidak menggantikan penanganan aman terhadap data tidak tepercaya. Nonce membatasi eksekusi, sementara aplikasi tetap bertanggung jawab atas data flow yang membentuk dokumen serta code yang dimuat oleh trusted script.
Referensi
- MDN, Content Security Policy (CSP): https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP
- MDN, Content-Security-Policy header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy