JSON Toolkit

איך XSS קורה דרך JSON

שורה תחתונה: JSON לא מבצע שום דבר בעצמו. XSS קורה ברגע שמתייחסים אליו כ-HTML — חיבור מחרוזות בצד השרת, innerHTML בצד הלקוח, או הטמעת JSON ישירות בתג script.

בינוניכ-4 דקות קריאהפורסם 2026-10-30עודכן 2026-10-30
שלוש דרכים שבהן JSON הופך ל-XSS ואיך למנוע אותן

שורה תחתונה: JSON לעולם לא מבצע שום דבר בעצמו — סגרו קודם את שלושת נתיבי הפלט: עשו escaping בצד השרת לפי הקשר, השתמשו ב-textContent במקום innerHTML, והחליפו < ב-\u003c כשמטמיעים JSON.

{"name": "<img src=x onerror=alert(1)>"} הוא נתון תקין. האם הוא מסוכן תלוי לגמרי במקום שבו שמים אותו.

כניסה ראשונה: בניית מחרוזות בצד השרת

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

הדפדפן מפרס את התגיות בתוך data.name. ה-JSON כאן הוא רק המכל; האשמה היא escaping להקשר הלא נכון.

תיקון: השתמשו ב-escaping ברירת המחדל של מנוע התבניות (<%= %> ב-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 הם ויתור מפורש.

אם באמת צריך טקסט עשיר, עשו סניטיזציה עם allowlist (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 hijacking — דפדפנים ישנים ביצעו JSON שנטען דרך <script src>; הגדרה מחדש של Array הדליפה את התוכן. דפדפנים מודרניים תיקנו זאת, ו-Content-Type: application/json יחד עם X-Content-Type-Options: nosniff סוגר את השאר.

שאריות JSONP — שם callback שנשלט על ידי המשתמש הוא ביצוע קוד שרירותי לפי תכנון. אל תשתמשו בו במערכות חדשות.

צ'ק ליסט

  • כל מקום שבו שדה JSON מגיע ל-HTML עובר escaping לפי ההקשר שלו (HTML, attribute, JS, URL)
  • אין innerHTML, v-html או dangerouslySetInnerHTML שצורכים מחרוזות API
  • JSON מוטמע עושה escaping ל-<, > ו-&
  • טקסט עשיר עובר סניטיזציה לפי allowlist, לא סינון blacklist
  • תגובות נושאות Content-Type: application/json ו-nosniff

שאלות ותשובות

למה JSON תקין עדיין יכול להפעיל XSS?

ה-JSON הוא רק טקסט ולעולם לא מתבצע; היותו תקין רק אומר שהוא נפרס. הסכנה מופיעה כשהוא נכתב להקשר HTML או script: הדפדפן מפרס את התגיות, או ש-</script> סוגר את הבלוק מוקדם והשאר רץ כקוד. האשמה היא ה-escaping החסר לפי הקשר הפלט, לא פורמט הנתונים.

האם להשתמש ב-textContent או ב-innerHTML כדי להציג שדות API?

עדיפו textContent: הוא מכניס את הערך כטקסט פשוט, כך שתגיות מוצגות מילולית. innerHTML מפרס סימון, כך ששדה API שמכיל <img onerror=...> מתבצע. {user.bio} של React ו-{{ user.bio }} של Vue יוצרים צומתי טקסט כברירת מחדל; dangerouslySetInnerHTML ו-v-html הם ויתור מפורש.

איך לעשות escaping ל-JSON שמוטמע בתג <script>?

כן. </script> בתוך הנתונים סוגר את הבלוק מוקדם וכל מה שאחריו רץ כסקריפט חדש. אחרי הסריאליזציה, החליפו <, > ו-& ב-\u003c, \u003e ו-\u0026: התוצאה עדיין JSON תקין, נפרסת באופן זהה, ולא יכולה יותר לסגור את התג.

קריאה נוספת