Content Security Policy dapat berisi daftar panjang host skrip yang diizinkan tetapi tetap memberikan kewenangan eksekusi lebih luas daripada yang dimaksud pembuat aplikasi. Sumber host seperti https://cdn.example.net mengizinkan resource skrip yang cocok dari origin tersebut; aturan itu tidak menyatakan respons individual atau keputusan aplikasi mana yang dipercaya. Saat host yang diizinkan juga menyajikan file yang dikendalikan pengguna, endpoint JSONP lama, atau resource executable lain di luar set yang dimaksud aplikasi, batas berbasis host dapat menjadi terlalu luas.

Kebijakan berbasis nonce mengambil jalur berbeda. Server menempatkan nilai yang tidak dapat diprediksi pada kebijakan script-src dan pada elemen skrip yang hendak diotorisasi untuk respons tersebut. Dengan source expression strict-dynamic dari CSP Level 3, kepercayaan yang diberikan kepada skrip yang diotorisasi nonce atau hash dapat diteruskan ke skrip yang dimuat secara dinamis oleh skrip tepercaya itu. Batas enforcement utama pun bergeser dari inventaris host statis ke kode yang menerima kewenangan bootstrap.

Nonce mengotorisasi elemen dalam satu respons

Nonce source memiliki bentuk 'nonce-<base64-value>'. Atribut nonce yang cocok pada elemen skrip mengizinkan elemen tersebut dieksekusi ketika kebijakan sebaliknya akan memblokirnya. Nilainya harus tidak dapat diprediksi dan dibuat terpisah untuk setiap respons HTTP yang menggunakannya.

Respons sederhana dapat berbentuk seperti ini:

Content-Security-Policy: script-src 'nonce-r4Nd0mBase64Value' 'strict-dynamic'; object-src 'none'; base-uri 'none'
<script nonce="r4Nd0mBase64Value" src="/assets/bootstrap.js"></script>

Properti keamanan berasal dari kepemilikan nonce khusus respons, bukan dari anggapan bahwa string tersebut tetap rahasia setelah browser menerima dokumen. Kode yang dapat menyuntikkan markup tetapi tidak dapat memprediksi nonce tidak dapat begitu saja menambahkan elemen skrip baru yang sudah terotorisasi sebelumnya.

Karena itu, pembuatan nonce berada pada batas respons sisi server. Pemakaian satu nonce tetap untuk banyak respons mengubahnya menjadi token otorisasi yang dapat digunakan kembali dan merusak properti yang membuat otorisasi berbasis nonce berguna. Cryptographically secure random generator sesuai untuk kebutuhan ini; counter, timestamp, request ID, dan nilai lain yang dapat diprediksi bukan penggantinya.

strict-dynamic mendelegasikan kewenangan pemuatan skrip

Nonce dapat mengotorisasi skrip bootstrap, tetapi pemuatan skrip berikutnya masih dapat tunduk pada source list yang tersisa. Aplikasi modern sering membuat elemen skrip saat runtime, sehingga pemeliharaan host source untuk setiap dependency dinamis dapat kembali menghasilkan allowlist yang luas.

'strict-dynamic' mengubah model itu pada user agent yang menerapkan perilaku CSP Level 3. Skrip yang dipercaya melalui nonce atau hash valid dapat meneruskan kepercayaan kepada skrip yang dimuat melalui pembuatan skrip non-parser-inserted. Kebijakan dapat mengotorisasi set bootstrap kecil lalu membiarkan kode tepercaya tersebut memilih resource skrip berikutnya.

Secara konseptual, rantai kepercayaannya adalah:

respons HTTP
    |
    +-- nilai nonce dalam CSP
            |
            +-- skrip bootstrap yang cocok
                    |
                    +-- pemuatan skrip terprogram
                            |
                            +-- pemuatan skrip terprogram

Ini adalah delegasi, bukan persetujuan origin. Skrip yang dimuat secara dinamis tidak menjadi aman karena host-nya tercantum dalam sebuah daftar. Skrip itu berjalan karena kode yang sudah memegang kewenangan eksekusi memilihnya melalui jalur yang meneruskan kepercayaan.

Perbedaan tersebut juga menetapkan failure mode utama: skrip bootstrap tepercaya yang mengubah data yang dikendalikan penyerang menjadi URL skrip dapat mendelegasikan kewenangannya kepada resource pilihan penyerang. CSP tidak memeriksa maksud aplikasi di dalam kode tersebut.

Parser insertion dan programmatic insertion memiliki batas berbeda

Penerusan kepercayaan pada strict-dynamic terkait dengan cara skrip diperkenalkan. Skrip yang dibuat kode tepercaya melalui API seperti document.createElement('script') dapat masuk ke rantai kepercayaan dinamis. Elemen skrip parser-inserted yang disuntikkan sebagai markup tidak otomatis mewarisi kepercayaan itu hanya karena skrip tepercaya menyebabkan sebagian HTML diparsing.

Perbedaan ini berpengaruh pada arsitektur aplikasi. Loader yang secara eksplisit membentuk elemen skrip dari module map internal tetap menghadirkan permukaan kewenangan yang lebih sempit daripada komponen yang menerima HTML arbitrer berisi tag skrip.

Contoh berikut menempatkan keputusan sensitif pada pembentukan src:

const script = document.createElement('script');
script.src = selectModuleUrl(moduleName);
document.head.appendChild(script);

Jika moduleName dapat dipengaruhi penyerang dan selectModuleUrl mengizinkan URL arbitrer, loader tepercaya menjadi execution gadget. Rantai kepercayaan CSP bekerja sesuai konfigurasi; aplikasi telah mendelegasikan kewenangan terlalu luas melalui kode tepercaya.

Desain yang lebih sempit membatasi pilihan sebelum elemen skrip dibuat:

const modules = {
  charts: '/assets/charts.js',
  editor: '/assets/editor.js',
};

const src = modules[moduleName];
if (!src) {
  throw new Error('unsupported module');
}

const script = document.createElement('script');
script.src = src;
document.head.appendChild(script);

Kebijakan dan loader kini menegakkan bagian batas yang berbeda. CSP menentukan kode bootstrap mana yang menerima kewenangan. Logika aplikasi menentukan dependency dinamis mana yang boleh dipilih kode tersebut.

Host source menjadi data kompatibilitas pada browser pendukung

Sebuah kebijakan dapat menggabungkan nonce, 'strict-dynamic', serta host atau scheme source. Pada user agent yang mendukung strict-dynamic, allowlist host dan scheme dalam ekspresi script-src yang sama diabaikan untuk pemilihan skrip ketika model strict dynamic berlaku. User agent lama yang tidak menerapkan perilaku tersebut dapat memakai host source sebagai data fallback kebijakan.

Pola kompatibilitas itu perlu ditinjau dengan cermat karena dua kebijakan efektif dapat berlaku pada populasi browser yang digunakan. Jalur modern berbasis kepercayaan nonce atau hash beserta delegasi. Jalur fallback mungkin tetap berbasis origin.

Penambahan 'self' atau domain CDN di samping 'strict-dynamic' tidak boleh dianggap sebagai pembatas tambahan bagi browser pendukung. Source expression tersebut dapat melayani kasus fallback, sedangkan jalur enforcement modern mengikuti graf kepercayaan yang didelegasikan.

Secara operasional, persyaratan dukungan browser adalah bagian dari desain keamanan. Jika aplikasi harus mendukung klien tanpa perilaku CSP yang dituju, allowlist fallback perlu mendapat pemeriksaan setara dengan kebijakan berbasis host konvensional.

Nonce tidak melakukan sanitasi markup

CSP berbasis nonce bukan HTML sanitizer dan tidak membuat konstruksi DOM arbitrer menjadi aman. Injeksi ke konteks event handler, penanganan URL berbahaya, DOM clobbering, atau script gadget khusus aplikasi dapat menimbulkan konsekuensi yang tidak terbatas pada penambahan elemen <script> baru.

Pemisahan yang sama berlaku pada template server. Jika teks yang dikendalikan penyerang dapat keluar ke atribut nonce atau ke body inline script tepercaya, nonce tidak memperbaiki cacat templating tersebut. Mekanisme otorisasi mengasumsikan aplikasi hanya memberikan nonce kepada elemen skrip yang memang hendak dipercaya dan menjaga data tidak tepercaya di luar konteks executable.

CSP paling kuat ketika diperlakukan sebagai lapisan enforcement independen di sekitar aplikasi yang juga mempertahankan output encoding, konstruksi DOM yang aman, serta batas data-ke-kode yang sempit.

Caching mengubah lokasi pembuatan nonce

Nonce per respons berinteraksi langsung dengan caching HTML. Jika shared cache menyimpan respons HTML lengkap yang berisi header CSP dan markup dengan nonce, pemutaran ulang respons tersebut juga memutar ulang nonce. Header dan dokumen tetap konsisten satu sama lain, tetapi nilainya tidak lagi unik untuk respons yang baru dibuat.

Deployment dapat menanganinya dengan beberapa cara: membuat nonce setelah batas shared cache, menghindari shared caching untuk HTML yang memuat nonce, atau memakai kebijakan berbasis hash saat konten bootstrap inline yang diotorisasi bersifat statis dan cocok untuk hashing. Pilihan yang tepat bergantung pada arsitektur rendering dan cache.

Invarian yang harus dipertahankan adalah ikatan antara nilai kebijakan dan elemen skrip yang dimaksud dalam respons yang sama. Penulisan ulang header pada satu layer dan penulisan ulang HTML pada layer lain dapat memutus ikatan tersebut dan menyebabkan skrip terblokir atau nonce digunakan kembali tanpa sengaja.

Report-Only adalah bukti observasi, bukan enforcement

Content-Security-Policy-Report-Only dapat menampilkan pelanggaran kebijakan tanpa memblokirnya. Mode ini berguna saat migrasi karena aplikasi yang sudah berjalan sering memiliki jalur eksekusi inline, loader pihak ketiga, atau pembuatan skrip saat runtime yang akan terlihat oleh kebijakan lebih ketat.

Report perlu diperlakukan sebagai telemetry. Tidak adanya report bukan bukti bahwa setiap jalur eksekusi relevan sudah dijalankan, dan kebijakan report-only tidak menyediakan batas pemblokiran. Peralihan ke enforcement memerlukan kebijakan yang sesuai dengan desain bootstrap dan pemuatan dinamis aplikasi yang sebenarnya.

Deployment yang matang juga dapat mempertahankan reporting di sekitar kebijakan enforcement untuk mendeteksi regresi dan percobaan eksekusi yang tidak diharapkan. Pengumpulan report tetap memerlukan kontrol operasional normal: penanganan laju, tinjauan privasi, kebijakan retensi, serta sikap untuk tidak memperlakukan report buatan penyerang sebagai fakta tepercaya.

Skrip bootstrap menjadi principal keamanan

Dengan strict-dynamic, target pemeriksaan terpenting bukan panjang allowlist host. Target utamanya adalah kode yang pertama kali menerima otorisasi nonce atau hash serta setiap jalur yang memungkinkan kode tersebut membuat eksekusi skrip lanjutan.

Pemeriksaan itu memiliki pertanyaan konkret: skrip mana yang menerima nonce, fungsi mana yang dapat membentuk URL skrip, input apa yang mencapai fungsi tersebut, module map mana yang membatasinya, serta loader pihak ketiga mana yang dapat memperpanjang rantai. File bootstrap kecil dapat membawa kewenangan luas meski header CSP terlihat minimal.

Model ini memberi CSP batas yang lebih tajam, tetapi juga memusatkan kepercayaan. Pembuatan nonce harus tetap khusus per respons, pemberian nonce harus tetap sempit, dan loader tepercaya tidak boleh mengubah string tidak tepercaya menjadi dependency executable. Kebijakan dapat menetapkan mekanisme delegasi; aplikasi tetap menetapkan keputusan yang dibuat dengan kewenangan hasil delegasi tersebut.