Bagaimana XSS berlaku melalui JSON
Inti pati: JSON tidak pernah melaksanakan dengan sendirinya. XSS berlaku pada saat anda menganggapnya sebagai HTML — penggabungan rentetan di pelayan, innerHTML di frontend, atau membenamkan JSON terus ke dalam tag skrip.

Pokoknya: JSON tidak pernah melaksanakan dengan sendirinya — tutup tiga laluan output dahulu: escape di pelayan mengikut konteks, guna textContent dan bukan innerHTML, dan ganti < dengan \u003c apabila membenamkan JSON.
{"name": "<img src=x onerror=alert(1)>"} ialah data yang sah. Sama ada ia berbahaya bergantung sepenuhnya pada tempat anda meletakkannya.
Titik masuk satu: pembinaan rentetan di pelayan
res.send(`<div>Hello, ${data.name}</div>`);
Pelayar menghuraikan tag di dalam data.name. JSON di sini hanyalah bekas; kesalahannya ialah escape untuk konteks yang salah.
Pembetulan: guna escape lalai enjin templat (<%= %> dalam EJS, {{ }} dalam Vue dan Django). Elakkan <%- %>, v-html dan |safe untuk apa-apa yang dikawal pengguna.
Titik masuk dua: innerHTML
el.innerHTML = user.bio; // menghuraikan markup
el.textContent = user.bio; // memasukkan teks
{user.bio} dalam React dan {{ user.bio }} dalam Vue mencipta nod teks dan selamat secara lalai. dangerouslySetInnerHTML dan v-html ialah penolakan eksplisit.
Jika anda benar-benar memerlukan teks kaya, sanitasi dengan senarai putih (DOMPurify dan seumpamanya) dan bukannya mempercayai backend.
Titik masuk tiga: membenamkan ke dalam tag skrip
<script>
window.__DATA__ = {"name": "x</script><script>alert(1)</script>"};
</script>
</script> di dalam data menutup blok lebih awal dan segala-galanya selepasnya berjalan sebagai skrip baharu. Ini ialah kes yang paling selalu terlepas.
JSON.stringify(data)
.replace(/</g, '\\u003c')
.replace(/>/g, '\\u003e')
.replace(/&/g, '\\u0026');
Masih JSON yang sah, serupa selepas penghuraian, tidak lagi dapat menutup tag. Next.js dan Nuxt melakukan perkara yang sama untuk __NEXT_DATA__ dan __NUXT__.
Dua jiran yang patut diketahui
Pembajakan JSON — pelayar lama melaksanakan JSON yang dimuatkan melalui <script src>; mentakrif semula Array membocorkan kandungannya. Pelayar moden telah membetulkannya, dan Content-Type: application/json serta X-Content-Type-Options: nosniff menutup selebihnya.
Sisa JSONP — nama panggil balik yang dikawal pengguna ialah pelaksanaan kod sewenang-wenangnya secara reka bentuk. Jangan gunakannya dalam sistem baharu.
Senarai semak
- Setiap tempat medan JSON sampai ke HTML di-escape mengikut konteksnya (HTML, atribut, JS, URL)
- Tiada
innerHTML,v-htmlataudangerouslySetInnerHTMLyang menggunakan rentetan API - JSON yang dibenamkan me-escape
<,>dan& - Teks kaya melalui sanitasi senarai putih, bukan penapisan senarai hitam
- Respons membawa
Content-Type: application/jsondannosniff
Soalan Lazim
Mengapa JSON yang sah masih boleh mencetuskan XSS?
JSON hanyalah teks dan tidak pernah melaksanakan; menjadi sah hanya bermaksud ia dihuraikan. Bahaya muncul apabila ia ditulis ke dalam konteks HTML atau skrip: pelayar menghuraikan tag, atau </script> menutup blok lebih awal dan selebihnya berjalan sebagai kod. Kesalahannya ialah escape sedar konteks yang hilang semasa output, bukan format data.
Patutkah saya guna textContent atau innerHTML untuk memaparkan medan API?
Utamakan textContent: ia memasukkan nilai sebagai teks biasa, jadi tag dipaparkan secara literal. innerHTML menghuraikan markup, jadi medan API yang mengandungi <img onerror=...> melaksanakan. {user.bio} dalam React dan {{ user.bio }} dalam Vue mencipta nod teks secara lalai; dangerouslySetInnerHTML dan v-html ialah penolakan eksplisit.
Bagaimana saya harus me-escape JSON yang dibenamkan ke dalam tag <script>?
Ya. </script> di dalam data menutup blok lebih awal dan segala-galanya selepasnya berjalan sebagai skrip baharu. Selepas mensirikan, ganti <, > dan & dengan \u003c, \u003e dan \u0026: hasilnya masih JSON yang sah, dihuraikan secara serupa, dan tidak lagi dapat menutup tag.