JSON Toolkit

JSON के ज़रिए XSS कैसे होता है

मुख्य बात: JSON अपने आप कभी execute नहीं होता। XSS उस पल होता है जब आप उसे HTML की तरह मानते हैं — server-side string concatenation, frontend innerHTML, या JSON को सीधे script tag में inline करना।

मध्यम~4 मिनट पढ़ें2026-10-30 को प्रकाशित2026-10-30 को अपडेट किया गया
JSON तीन तरीकों से XSS बनता है और कैसे रोकें

मुख्य बात: JSON अपने आप कभी execute नहीं होता — पहले तीन output रास्ते बंद करें: server-side में context के अनुसार escape करें, innerHTML के बजाय textContent उपयोग करें, और JSON inline करते समय < को \u003c से बदलें।

{"name": "<img src=x onerror=alert(1)>"} वैध डेटा है। यह ख़तरनाक है या नहीं, यह पूरी तरह इस पर निर्भर है कि आप इसे कहाँ रखते हैं।

पहला प्रवेश: server-side string बनाना

res.send(`<div>Hello, ${data.name}</div>`);

Browser data.name के अंदर के tags parse करता है। यहाँ JSON केवल पात्र है; दोष गलत context के लिए escaping का है।

समाधान: templating engine का डिफ़ॉल्ट escaping उपयोग करें (EJS में <%= %>, Vue और Django में {{ }})। उपयोगकर्ता-नियंत्रित किसी भी चीज़ के लिए <%- %>, v-html और |safe से बचें।

दूसरा प्रवेश: innerHTML

el.innerHTML = user.bio;    // markup parse करता है
el.textContent = user.bio;  // text डालता है

React का {user.bio} और Vue का {{ user.bio }} text nodes बनाते हैं और डिफ़ॉल्ट रूप से सुरक्षित हैं। dangerouslySetInnerHTML और v-html स्पष्ट opt-outs हैं।

अगर सचमुच rich text चाहिए, तो backend पर भरोसा करने के बजाय allowlist (DOMPurify वग़ैरह) से sanitise करें।

तीसरा प्रवेश: script tag में inline करना

<script>
  window.__DATA__ = {"name": "x</script><script>alert(1)</script>"};
</script>

डेटा के अंदर का </script> ब्लॉक को समय से पहले बंद कर देता है और उसके बाद सब कुछ नए script के रूप में चलता है। यह सबसे अधिक छूट जाने वाला मामला है।

JSON.stringify(data)
  .replace(/</g, '\\u003c')
  .replace(/>/g, '\\u003e')
  .replace(/&/g, '\\u0026');

अब भी वैध JSON, parsing के बाद बिल्कुल वही, पर अब tag बंद नहीं कर सकता। Next.js और Nuxt __NEXT_DATA__ और __NUXT__ के लिए यही करते हैं।

दो पड़ोसी जिन्हें जानना ज़रूरी है

JSON hijacking — पुराने browsers <script src> से लोड किए गए JSON को execute कर देते थे; Array को फिर से परिभाषित करके सामग्री leak हो जाती थी। आधुनिक browsers ने इसे ठीक कर दिया, और Content-Type: application/json तथा X-Content-Type-Options: nosniff बाकी बंद कर देते हैं।

JSONP के अवशेष — उपयोगकर्ता-नियंत्रित callback नाम डिज़ाइन से ही मनमाना code execution है। नए सिस्टम में इसका उपयोग न करें।

चेकलिस्ट

  • JSON फ़ील्ड जहाँ भी HTML तक पहुँचता है, वहाँ उसके context के लिए escaped है (HTML, attribute, JS, URL)
  • कोई innerHTML, v-html या dangerouslySetInnerHTML API strings नहीं खा रहा
  • Inline किया गया JSON <, > और & escape करता है
  • Rich text allowlist sanitisation से गुज़रता है, blacklist filtering से नहीं
  • Responses में Content-Type: application/json और nosniff है

FAQ

वैध JSON फिर भी XSS क्यों पैदा कर सकता है?

JSON केवल टेक्स्ट है और कभी execute नहीं होता; वैध होने का मतलब बस यह है कि वह parse होता है। ख़तरा तब सामने आता है जब इसे HTML या script context में लिखा जाता है: browser tags parse करता है, या </script> ब्लॉक को समय से पहले बंद कर देता है और बाकी code के रूप में चलता है। दोष output पर context-aware escaping की कमी है, डेटा फ़ॉर्मैट का नहीं।

API फ़ील्ड render करने के लिए textContent या innerHTML उपयोग करूँ?

textContent को प्राथमिकता दें: यह मान को सादे टेक्स्ट के रूप में डालता है, इसलिए tags ज्यों के त्यों दिखते हैं। innerHTML markup parse करता है, इसलिए <img onerror=...> वाला API फ़ील्ड execute हो जाता है। React का {user.bio} और Vue का {{ user.bio }} डिफ़ॉल्ट रूप से text nodes बनाते हैं; dangerouslySetInnerHTML और v-html स्पष्ट opt-outs हैं।

<script> tag में inline किए गए JSON को कैसे escape करूँ?

हाँ। डेटा के अंदर का </script> ब्लॉक को समय से पहले बंद कर देता है और उसके बाद सब कुछ नए script के रूप में चलता है। Serialise करने के बाद <, > और & को \u003c, \u003e और \u0026 से बदलें: परिणाम अब भी वैध JSON है, वैसे ही parse होता है, और अब tag बंद नहीं कर सकता।

आगे पढ़ें