JSON Toolkit

كيف تحدث XSS عبر JSON

الخلاصة: JSON لا يُنفَّذ بنفسه أبدًا. تحدث XSS في اللحظة التي تتعامل فيها معه كـHTML — بدمج السلسلة على الخادم، أو innerHTML في الواجهة، أو إدراج JSON مباشرة داخل وسم script.

متوسطقراءة نحو 4 دقيقةنُشر في 2026-10-30حُدِّث في 2026-10-30
ثلاث طرق يصير بها JSON سببًا لـXSS وكيف تمنعها

الخلاصة: JSON لا يُنفَّذ بنفسه أبدًا — أغلق مسارات المخرج الثلاثة أولًا: هرّب على الخادم بحسب السياق، واستخدم textContent بدلًا من innerHTML، واستبدل < بـ\u003c عند إدراج JSON.

{"name": "<img src=x onerror=alert(1)>"} بيانات صالحة. وكونها خطرة أم لا يتوقف كليًا على مكان وضعها.

المدخل الأول: بناء السلسلة على الخادم

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

يحلل المتصفح الوسوم داخل data.name. ‏JSON هنا مجرد الحاوية؛ والخطأ هو الهروب لسياق خاطئ.

الإصلاح: استخدم الهروب الافتراضي لمحرك القوالب (<%= %> في EJS، و{{ }} في Vue وDjango). وتجنب <%- %> وv-html و|safe لأي شيء يتحكم فيه المستخدم.

المدخل الثاني: innerHTML

el.innerHTML = user.bio;    // parses markup
el.textContent = user.bio;  // inserts text

‏{user.bio} في React و{{ user.bio }} في Vue ينشئان عقد نصية وهما آمنان افتراضيًا. أما dangerouslySetInnerHTML وv-html فانسحاب صريح.

إن كنت تحتاج فعلًا إلى نص منسق، فنقّه بقائمة سماح (DOMPurify وما شابه) بدلًا من الثقة بالخادم.

المدخل الثالث: الإدراج داخل وسم script

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

‏</script> داخل البيانات يغلق الكتلة مبكرًا وكل ما بعده يُنفَّذ كسكربت جديد. هذه الحالة الأكثر تفويتًا.

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

‏JSON صالح ما يزال، مطابق بعد التحليل، وغير قادر بعد الآن على إغلاق الوسم. ويفعل Next.js وNuxt الشيء نفسه مع __NEXT_DATA__ و__NUXT__.

جاران يستحسن معرفتهما

اختطاف JSON — كانت المتصفحات القديمة تنفذ JSON المحمّل عبر <script src>؛ وإعادة تعريف Array سرّبت المحتويات. أصلحتها المتصفحات الحديثة، وContent-Type: application/json مع X-Content-Type-Options: nosniff يغلق الباقي.

بقايا JSONP — اسم دالة رد اتصال يتحكم فيه المستخدم هو تنفيذ كود اعتباطي بالتصميم. لا تستخدمه في أنظمة جديدة.

قائمة التحقق

  • كل مكان يصل فيه حقل JSON إلى HTML يُهرَّب لسياقه (HTML، والسمة، وJS، وURL)
  • لا innerHTML ولا v-html ولا dangerouslySetInnerHTML تستهلك سلاسل API
  • JSON المضمّن يهرّب < و> و&
  • النص المنسق يمر عبر تنقية بقائمة سماح، لا تصفية بقائمة حظر
  • الاستجابات تحمل Content-Type: application/json وnosniff

الأسئلة الشائعة

لماذا يمكن أن يثير JSON صالح XSS رغم ذلك؟

‏JSON مجرد نص ولا يُنفَّذ أبدًا؛ وكونه صالحًا يعني فقط أنه يُحلَّل. تظهر الخطورة عندما يُكتب في سياق HTML أو script: فيحلل المتصفح الوسوم، أو يغلق </script> الكتلة مبكرًا فيُشغَّل الباقي ككود. والخطأ هو غياب الهروب الواعي بالسياق عند الإخراج، لا تنسيق البيانات.

هل أستخدم textContent أم innerHTML لعرض حقول API؟

رجّح textContent: فهو يدرج القيمة كنص عادي، فتُعرض الوسوم حرفيًا. أما innerHTML فيحلل الترميز، فيُشغَّل حقل API يحتوي على <img onerror=...>. و{user.bio} في React و{{ user.bio }} في Vue ينشئان عقد نصية افتراضيًا؛ وdangerouslySetInnerHTML وv-html انسحاب صريح.

كيف أهرّب JSON المضمّن داخل وسم <script>؟

نعم. ‏</script> داخل البيانات يغلق الكتلة مبكرًا وكل ما بعده يُنفَّذ كسكربت جديد. بعد التسلسل، استبدل < و> و& بـ\u003c و\u003e و\u0026: فتبقى النتيجة JSON صالحًا، ويُحلَّل بالطريقة نفسها، ولا يستطيع بعد الآن إغلاق الوسم.

قراءة إضافية