Nonce Content Security Policy Mengotorisasi Elemen Script Tertentu
JavaScript inline menimbulkan batas yang sulit bagi Content Security Policy yang ketat. Sebuah halaman mungkin memerlukan blok bootstrap kecil yang dibuat aplikasi, sementara script inline lain harus tetap diblokir. Mengizinkan seluruh eksekusi inline dengan 'unsafe-inline' menghilangkan banyak manfaat script-src.
Nonce memberi mekanisme yang lebih sempit pada sebuah respons. Server menghasilkan nilai yang tidak dapat diprediksi untuk respons tersebut, menempatkannya dalam source list CSP, lalu memasang nilai yang sama hanya pada elemen script yang memang boleh dieksekusi.
Header dan elemen membawa nilai yang sama
Sebuah respons dapat mengirim policy seperti:
Content-Security-Policy: script-src 'nonce-r4nd0mBase64Value'Dokumen terkait dapat menandai script yang disetujui:
<script nonce="r4nd0mBase64Value">
window.appConfig = { mode: "production" };
</script>Browser yang mendukung mekanisme ini membandingkan nonce elemen dengan nonce source pada policy aktif. Nilai yang cocok membuat elemen tersebut memenuhi syarat directive. Script inline tanpa nonce yang diterima tetap diblokir kecuali source expression lain mengotorisasinya.
Nonce adalah metadata otorisasi untuk elemen. Nonce bukan tanda tangan kriptografis atas isi script dan tidak membuktikan bahwa isi script aman.
Nonce harus baru dan tidak dapat diprediksi
Nonce yang dipakai ulang menjadi token stabil yang mungkin dapat disalin atau ditargetkan oleh markup hasil injeksi. Karena itu, nilainya perlu dibuat dengan sumber acak yang aman secara kriptografis dan diganti pada setiap respons yang memakai otorisasi berbasis nonce.
request A -> nonce A -> CSP A + dokumen A
request B -> nonce B -> CSP B + dokumen B
request C -> nonce C -> CSP C + dokumen CProperti pentingnya bukan format yang mudah dibaca manusia. Yang dibutuhkan adalah tingkat ketidakpastian yang memadai selama umur respons. Implementasi umumnya mengenkode byte acak agar nilainya aman ditempatkan pada header HTTP dan atribut HTML.
Nonce tidak seharusnya diturunkan dari timestamp, counter, username, nama route, atau nilai lain yang dapat diprediksi penyerang. Nonce juga tidak semestinya berubah menjadi secret aplikasi berumur panjang.
Penempatan pada template menjadi bagian batas keamanan
CSP berbasis nonce bergantung pada server yang memasang nonce hanya pada elemen script tepercaya. Pola template yang menyalin nonce ke setiap node script merusak batas seleksi tersebut.
Sebagai contoh, helper rendering dapat menerima nonce respons dan memakainya hanya pada lokasi script yang eksplisit:
<script nonce="{{ .CSPNonce }}" src="/assets/bootstrap.js"></script>Aplikasi tetap harus mencegah data template berubah menjadi markup. Jika input yang dikendalikan penyerang dapat menyisipkan atribut ke elemen script yang sudah diotorisasi, atau mengubah isi script inline yang sudah diotorisasi, nonce bukan lagi satu-satunya batas yang relevan.
Karena itu, deployment nonce melengkapi output encoding, templating yang aman, dan konstruksi DOM yang hati-hati. Nonce tidak menggantikan kontrol tersebut.
Script eksternal juga dapat membawa nonce
Nonce tidak terbatas pada blok inline. Elemen script dengan src juga dapat membawa nonce:
<script nonce="r4nd0mBase64Value" src="/assets/app.js"></script>Pola ini dapat mendukung policy yang mengotorisasi elemen script melalui nonce, bukan host allowlist yang luas. Hasil akhirnya tetap bergantung pada keseluruhan policy script-src dan dukungan browser terhadap source expression yang dipakai.
Nonce pada script eksternal tidak memverifikasi byte yang diambil. Subresource Integrity menangani properti berbeda dengan memeriksa isi resource terhadap hash yang dideklarasikan. Keduanya dapat dipakai bersama, tetapi menyelesaikan persoalan yang berbeda.
Cache harus mempertahankan pasangan header dan dokumen
Nonce respons muncul pada header CSP dan HTML yang memuat elemen terotorisasi. Menyimpan hanya salah satu sisi di cache, menulis ulang satu sisi secara terpisah, atau menggabungkan dokumen dari cache dengan header baru akan merusak pasangan tersebut.
CSP: nonce=A
HTML: nonce=A -> cocok
CSP: nonce=B
HTML: nonce=A -> tidak cocokDesain cache harus memperlakukan policy dan dokumen sebagai satu unit respons. Sistem yang membuat HTML di origin lalu memodifikasi header di proxy memerlukan perhatian khusus karena pembuatan nonce pada satu lapisan harus tetap sinkron dengan pembuatan markup pada lapisan lain.
HTML statis juga mengubah pertimbangannya. Nonce per respons memerlukan komponen yang mampu menghasilkan markup khusus untuk tiap respons. Hash source dapat lebih sesuai untuk script inline yang immutable karena policy dapat mengotorisasi isi script tetap tanpa mengubah markup pada setiap request.
Nonce tidak melakukan sanitasi JavaScript dinamis
Script yang sudah diotorisasi tetap dapat mengeksekusi data berbahaya jika aplikasi memasukkan input tanpa escaping ke sintaks JavaScript.
<script nonce="{{ .CSPNonce }}">
const profile = {{ .SerializedProfile }};
</script>Nonce menyatakan bahwa elemen script tersebut diotorisasi oleh policy. Nonce tidak menyatakan bahwa .SerializedProfile telah diserialisasi secara aman untuk konteks JavaScript.
Data yang masuk ke script perlu memakai serializer yang menghasilkan output valid dan sesuai konteks. Prinsip yang sama berlaku ketika script terotorisasi kemudian menulis ke DOM: otorisasi CSP tidak membuat DOM sink yang tidak aman menjadi aman.
Cakupan policy tetap menentukan hasil
Nonce dievaluasi di dalam directive CSP, sehingga policy di sekitarnya menentukan perannya. script-src dapat memuat nonce source bersama host source, hash, atau keyword lain. Menambahkan nonce tidak otomatis menghapus izin yang lebih luas yang sudah ada.
Karena itu, review deployment nonce perlu membaca seluruh effective policy. Nonce yang dibuat dengan ketat memberi manfaat terbatas jika source expression lain masih mengizinkan eksekusi script dari lokasi yang tidak dimaksudkan aplikasi sebagai sumber tepercaya.
Policy report-only dapat membantu mengamati kerusakan saat rollout:
Content-Security-Policy-Report-Only: script-src 'nonce-r4nd0mBase64Value'Mode report-only mencatat pelanggaran policy pada browser yang mendukungnya, tetapi tidak menegakkan pembatasan. Enforcement memerlukan header Content-Security-Policy.
Dekatkan pembuatan nonce dengan konstruksi respons
Desain yang paling jelas menempatkan pembuatan nonce, konstruksi CSP, dan rendering HTML dalam jalur request yang sama. Dengan begitu, umur satu respons terlihat langsung pada code dan peluang perbedaan antara header dengan markup menjadi lebih kecil.
Policy berbasis nonce paling kuat ketika asumsinya tetap sempit: nilainya tidak dapat diprediksi, selalu baru untuk setiap respons, template memasangnya hanya pada elemen script yang dimaksudkan, dan bagian policy lain tidak diam-diam membuka kembali eksekusi script secara luas. Properti tersebut membuat nonce menjadi token otorisasi yang presisi untuk elemen script tertentu, bukan sekadar atribut tambahan.