הזרקת קוד

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

הרבה פעמים מערכות אשר לא נחשבות לקריטיות (כלומר ה"ציבור" לא נחשף אליהן), הן הפתח לפגיעה יותר חמורה מאשר מערכות קריטיות (חשוף בעולם האינטרנט). נגיד אם יש לי גישה ל switch מנוהל באמצעות HTTP, ואני מוצא שם XSS או SQL Injection, עד כמה מסובך להשיג את סיסמת המנהל למערכת ? ומכאן עד כמה מסובך לנחש את שאר הסיסמאות למערכות השונות ? עד כמה מסובך לקבל אח"כ "אינטרנט בחינם" או עוד הרבה דברים אחרים, כולל נזק אמיתי לארגון במטרה לעשות לו נזק ?

יותר מזה, הרבה מתכנתים אף פעם לא לומדים להבין את המשמעות של הזרקת קוד, ולא חושבים בכלל לכיוון. כבר שמעתי ממתכנת .NET שמצאתי לו SQL Injection "אבל אתה לא באמת יכול לשנות לי כלום כי יש לי Javascript שמאפשר רק לתווים מסויימים לעבור", ולקח לי 2 דקות להראות לו איך אני עוקף את ה"הגנה" הזו…

העניין הוא שהזרקת קוד זה לא רק Cross Site Scripting (כלומר XSS) או SQL Injection, אלא אני ממש רואה מקומות שמשתמשים ב eval לקוד שמגיע מהמשתמש, או ניתוח קבצי JSON למשל ב Javascript/Python במקום לנתח את הטקסט וליצור מזה מבנה אמיתי בשפה, פשוט עושים קיצורי דרך מסוכנים. תארו לכם שאני יכול להיכנס לשרת שלכם ולעשות כל העולה על רוחי אם אתם מריצים eval (או evil כמו שאני קורא לזה) ולהכניס קוד שפותח לי "שרת" לגישה ישירה ל bash ללא הזדהות וללא שהות, ולפעמים אפילו לקבל הרשאות root עליו.

תזכרו לבדוק כל מידע המגיע מכל מקור ולא רק שהוא לא אתם, ולא להשתמש בו כמו שהוא ולהגיד "יהיה בסדר". תזכרו כי Javascript הוא לא סוג של הגנה, והוא רץ בצד הלקוח, וככזה הלקוח יכול לבטל או לשנות אותו בכל עת שיחפוץ, ולכן אל תסמכו עליו שיעשה לכם את העבודה. הוא יותר כלי עזר שהמשתמשים שלכם יהיו מכוונים למה שאתם רוצים שהם יעשו, הם לא כלי עזר עבורכם בצד השרת.

אני מקווה שזה יעזור יותר לאנשים מאשר המאמרים שלי על תכנות בטוח.

18 מחשבות על “הזרקת קוד

  1. CooL_SPoT

    דווקא אני בדעה שלא צריך לבדוק בקשות שמגיעות, צריך פשוט לטפל בהן נכון במקומות השונים בקוד.
    א. כאשר שולחים שאילתת SQL, תמיד לשלוח אותה עם PREPARE, ולהעביר את הפרמטרים באופן נפרד
    ב. כאשר מציגים נתון שמתקבל ממשתמש באתר (למשל מכתובת הURL או בPOST), תמיד להשתמש בhtmlspecialchars()

  2. ik_5 מאת

    Cool_SPot, כאשר מראש אתה לא צריך את המידע החי כמו שהוא, פשוט תעיף כל דבר שלא צריך להיות שם מההתחלה. אם אתה מחפש משהו שיכול להכיל רק מספר, במקום להגיע למצב שאתה רק עובד עם Place Holders (או Binding במקומות אחרים), תעזור לעצמך הרבה לפני, על ידי הסרה של כל דבר שהוא לא מספר.

  3. CooL_SPoT

    ik_5
    אם יש לי שדה שהוא מספר אז:
    א. השדה בדאטאבייס יהיה מסוג מספר, כך שהוא לא יכול להכיל שום דבר אחר
    ב. אם חשוב לי לוודא את הקלט מהמשתמש אני אעשה את זה ברמת הJS, ואתן לו לרשום רק מספרים. זה לא סיכון אבטחה שאני לא מוודא את זה בסקריפט PHP

  4. ik_5 מאת

    טוב אם אתה חושב שאתה בטוח בהצלחה, כאשר תגלה יום אחד שהמידע שלך נעלם, או שפתאום משהו קרה לך למידע אז תבין.

    זה כל כך ישראלי להגיד "לי זה לא יקרה". להשתמש רק בכלי אחד זה לא פתרון לקבל הגנה. ג'אווהסקריפט ד"א זה לא עוד מנגנון.

  5. CooL_SPoT

    אמממ
    ההסבר שלך הוא מאוד אינפורמטיבי
    זה בכלל לא נשמע כמו "אני צודק ואין ואין לי דרך להוכיח לזה, אז אני אאיים שהמידע שלך יאבד, בלי להראות דוגמא בכלל", לא…

  6. קובי

    מה שעידו טוען הוא ש js אינה הגנה. js רצה בצד הלקוח ולתוקפים יש עליה שליטה מלאה, תוקף יכול למשל לבטל js לחלוטין, להשתמש במקופף, ובכלל אל להשתמש בדפדפן לצורך התקיפה.

    אם יש לי שדה ב post או get שלא בודק את המידע, אפשר לכתוב תכנית קטנה שתשלך לו מה שאנכנו רוצים. אנכנו לא נשתמש בדף ה html שלך, לא משנה מה הטופס שיצרתי רוצה לשלוח, ולא משנה מה ב js בדף שכתבתי עושה למידע.

  7. ik_5 מאת

    בנוסף להסבר של קובי, וזה מה שאני מנסה להבהיר זה שאתה עושה שימוש במידע שאתה כותב למסד הנתונים. אתה עושה שימוש בו לפני ואולי גם אחרי שכתבת. אתה עושה בו שימוש כאשר אתה שולף אותו וכו'. אני בטוח שאחרי שכתבת אותו במסד הנתונים אתה בטוח שהוא פחות מסוכן ?

    יותר מזה, האם אתה בודק למה שאילתא נכשלה ? כלומר "הזנת ערך לא מתאים ?"

    עכשיו נשאל אותך עוד שאלה. אתה יודע שגם MySQL וגם SQLite מכילים feature שלפעמים אתה יכול לשים טקסט כמספר ? למשל ב SQLIte הטיפוס הוא weak וזה מוגדר בתעוד כ feature. ב MySQL אני הצלחתי להזין לשדה מספרי מחרוזת של תווי מספרים, בעוד שבמסדי נתונים אחרים אני מקבל שגיאה שזה מחרוזת והוא מצפה למספר.
    נגיד ויש עכשיו באג במסד הנתונים שלך, והוא מאפשר לך להזין מחרוזת לשדה שהוא מסוג מספר, או מכיל את זה כ feature כדוגמת SQLite, מה אתה עושה אז ?

    בנוסף, מה קורה אם ה Placeholders שלך משתנים בקוד של PHP למשל, ולא כחלק ממסד הנתונים ומסתבר שיש באג ב Escaping שהוא עושה, או כמו שנתקלתי, תיד הוא מחליט שזה מחרוזת, איך אתה מתמודד עם זה ?

    בגלל זה אני אומר שPlaceholders זה חובה לשימוש, אבל לא כהגנה היחידה, אלא כחלק מהגנה כוללת. אם מראש אתה מנקה כל דבר שלא צריך להיות מהמידע שאתה מקבל (במידה ואתה יכול מן הסתם), אתה מוריד לך הרבה כאב ראש, וחוסך לך באגים שאתה אפילו לא מודע שיש לך בגלל שלא ניקית. נגיד אתה בטוח שבגלל שהשתמשת ב Placeholder זה מספר, אתה מדפיס אותו ללא escaping של html ומגלה XSS בגלל זה (והיו דברים מעולם).

    אני מקווה שההסבר הזה עוזר לך קצת יותר.

  8. CooL_SPoT

    אז רשמתי את 2 הכללים שאני משתמש בהם:
    א. תמיד להציג עם htmlspecialchars
    ב. תמיד לעשות prepare
    מבחינתי שהתוקף יבטל את הJS, זה לא משנה לי כלום!
    אני לא בודק עם הJS דברים קריטיים גם ככה, רק עוזר למשתמש להכניס תווים נכונים.

    לגבי זה שאתה מצליח להכניס תווים לשדה שהוא מספר, אין לי מושג על מה אתה מדבר, יש לי בדאטאבייס מסוג int, ולא משנה איזה תו אני מנסה להכניס, הוא לא נכנס, בוא תראה לי שאילתה שמכניסה תווים לשדה כזה…

    בוא אני אתן לכם קוד קצר ***ללא*** בדיקת משתנים (כמו שאתם אומרים שחייבים לעשות!) ותגידו לי איך אתם מזריקים לו קוד:
    http://pastebin.com/udQC20HE

    1. kobi

      1. יופי אנכנו מסכימים, מה שעידו אמר זה "אני לא בודק עם הJS דברים קריטיים". עידו טוען שיש מי שכן חושב שבדיקה עם js היא סוג של הגנה, ושניכם מסכימים שזו אינה הגנה.

      2. שוב אנכנו מסכימים, עידו טוען שצריך "תמיד לעשות prepare" . עידו טוען שיש אנשים שחושבים שאפשר לקחת את הנתונים שהמשתמש נותן כמו שהם. הוא רואה בכך בעיית אבטחה.

      3. בדוגמה שנתת ***יש*** בדיקת משתניים ע"י הפונקציה bind_param של php הפונקציה הזו בודקת את הקלט ולא נותנת לקלט לא חוקי להיכנס.

  9. ארתיום

    עידו, מספר הערות:

    Prepared-statement פותר אותך בכל בעיית הזרקת הקוד. כך שבאמת, אני לא חושב שלדבר על SQL Injections כעל בעיה "גדולה" היום פשוט מטעה ומוטעה. אין שום סיבה (אלא אם כן המפתח אידיוט גמור) שיהיה בקוד בעיות מסוג זה.

    בעיה שניה – eval – כל עוד אתה בצד שרת – כמובן אל תעשה לעולם, אם אתה בצד לקוח… ואתה שולח למשל JSON תקין מצד השרת – מה איכפת לך? בצד לקוח שיעשה מה שבא לו! (והוא גם באמת יכול לעשות מה שבא לו אין לך שליטה על זה). הבעיה אם אתה לא שולח משהו בדוק ללקוח – אז זאת בעיה, אבל היא כבר מסוג אחר.

    לגבי XSS – הבעיה פה עוד יותר מורכבת.

    אם אתה לא צריך לאפשר הצגת HTML אין לך **שום** בעיה, למשל ב-CppCMS אם אתה מציג משהו בתור תבנית, כברירת מחדל היא מקבלת escaping ואם אתה רוצה להכניס HTML אתה צריך לסמן באופן מפורש שאתה רוצה להכניס מחרוזת as-is – אני חושב שגם Django בגרסה אחרונה עושה את זה ולעשה, כל framework שמכבד את עצמו צריך לעשות דבר כזה ברירת מחדל, ואם לא… htmlspecialchars ודבר בסגנון פותרים את הבעיה.

    הבעיה מתחילה כשאתה כן רוצה לאפשר למשתמש להציג html. אם אתה מקפיד ואומר שמותר לך להציג רק תגים מסוג b, i, quote ללא פרמטרים והקוד לך בודק את זה בצורה מאוד קפדנית, אתה בסדר. אבל נניח שאתה כן רוצה להציג קישורים? הופה! עכשיו אני יכול להכניס ב-URL משהו בסגנון "javascript:alert('Got you');‎" – אז אתה מתחיל להגונן (בד"כ בדוק שזה מתחיל מאיזשהו witelist כמו http או https או ftp – ואז פתאום קישורים מקומיים כמו ‎/foo/bar/foobar.html לא עובדים… ואתה רוצה (טוב גם לזה יש פתרון יחסית פשוט – תכתוב תמיד קישורים מלאים). כנ"ל תמונות ועוד אלף ואחד דברים שפתאום לא עובדים.

    עכשיו אתה רוצה לאפשר style (כי אולי יש לך עורך עשיר כמו tiny-mice) – איזה נזק כבר style יכול לעשות? מסתבר שהמון – גם שם אפשר לדחוף קוד.

    בסופו של דבר במערכות כאלה אתה מגיע או – לא להציג html בכלל, לסמוך על משתמש רשום (רעיון רע) או לאפשר דברים מבוקרים בצורה מבוקרת – ופה אתה צריך להיות מומחה או להשתמש בספריה צד ג' שנכתבה ע"י מומחה וגם כויילה כמו שצריך קרי נותנת מספיק כוח כדי לעשות דברים יפים. כי שוב, אם **אתה** תתחיל לכייל אותה, אתה בקלות תכניס איזו פירצה.

    כך שהבעיה היא קצת יותר מורכבת ממה שאתה מציג והבעיות הבסיסיות הן מתרחשות רק למפתחים שלא צריכים לעסוק במקצוע הזה. ואם בא מפתח צעיר ללא ניסיון, צריך להעביר את הקוד שלו תחת review קפדני עד שיהיה לו מספיק ניסיון לא ליפול בשטויות.

    אגב – בעיה של מניעץ XSS היא באמת בעיה מאוד קשה כשאתה כן רוצה לאפשר להציג HTML די עשיר – כי יש מעט מאוד כלים שעושים את זה נכון.

    1. ik_5 מאת

      מה שאני מנסה להגיד זה ש place holders זה טוב אבל לא מספק.
      htmlspecialchars מצויין, אבל לא מספק. ד"א מה עם קידוד ל uri (ששונה מקידוד ל HTML) ?

      יותר מזה, קיבלת עכשיו ערך. ואתה משתמש בו בשביל פעולה מסויימת. איך אתה מגיב ברגע שמשהו לא תקין ? נגיד קיבלת מספר ואתה רוצה להשתמש בו לחישוב בצד השרת (או הלקוח זה לא משנה), אני יכול להזריק לך קוד שירוץ או ישבור את התוכנית שלך. מה אז ?

      זו הבעיה של eval גם בצד הלקוח. הרי XSS זה בצד הלקוח ולא בצד השרת. אם אני עושה עכשיו Eval על מידע, אני לא בהכרח יודע אם הוא הגיע מהשרת, אני רק משער את זה. מה קורה אם היה לי session hijack ? והמידע שאני מקבל לא מתאים למה שצריך להיות ? מה קורה אם יש man in the middle בגלל תוסף שיש לדפדפן ושם מוזרק קוד ? מה קורה אם המידע הזה שאני חושב שהוא בטוח כי הגיע מהשרת חוזר אלי לשרת ואני עדיין מניח שהוא בטוח כי המשתמש כביכול לא נגע בו ?

      זה הרבה מעבר. בגלל זה דבר ראשון אני מדבר על כך שתעיף כל דבר שלא צריך להיות במידה וניתן. כאשר לא ניתן לבצע את זה, תתחיל להשתמש בכלים או ליצור whitelist למה אתה מאפשר שיהיה, או שתלמד להשתשמש במידע בצורה שלא תפגע באף אחד (כי לא תמיד יש כלים מתאימים למה שאתה מחפש).

      להגיד אני רק עושה escaping ו prepare הקוד שלך לא מוגן, ואתה עדיין חשוף להרבה מאוד בעיות. סתם לדוגמא, אחת הבעיות הנפוצות בעבר ב PHP היה global variable זוכר את זה ?

      ועכשיו עוד שאלה, מה אם אני עושה לך variable splitting, כלומר ה escaping שלך יודע להתמודד עם זה, אבל המידע שלך לא יודע להתמודד עם זה ? או השרת שלך לא יודע להתמודד עם זה וכו'… יש כל כך הרבה בעיות מעבר שכוללות הזרקת קוד, שתבין ש XSS ו SQL Injection הם רק ההתחלה ולא כל התורה.

  10. ארתיום

    תראה עידו, בגדול אני מסכים איתך, פשוט צריך תמיד לשים גבול ל"פרנויה" כי ישנן שתי קיצוניות – לאפשר הכל ולסגור הכל. הראשונה גרועה כי היא גרוע נקודה, השניה לפעמים פוגעת ביכול להבין מה באמת יכול לקרות.

    בכל אופן לגבי לחבר מחרוזת ומשתנה – כדאי לעבוד עם שפות שהן type-safe, כמו למשל ב-python אתה צריך להמיר מחרוזת למספר כדי לחבר – בכל מקרה – יש אינספור בעיות מסוג זה, צריך להיות מודע.

    1. ik_5 מאת

      איפה בדיוק הפרנויה ?
      האם לבדוק exception כאשר אתה ממיר ממחרוזת למספר שלם זו פרנויה ?
      האם לבדוק שהתוכן שאתה מקבל עומד בקריטריונים (מבנה, לא התוכן עצמו) זו פרנויה ?

      האם כאשר מעלים לך תמונה, לבדוק שהתוכן שלה הוא באמת תמונה זו פרנויה ?

      זה בסדר שרם משתמש בJavascript וב Prepare, אבל אם המספר שהוא מצפה לא יכול להיות מעל 1024 והוא הכניס עכשיו מספר בטווח 2^32 מן הסתם יש בעיה למרות שאין SQL Injection, יכול להיות לך Integer Overflow, במסד הנתונים או בשפת התכנות שלך, או בחישוב שלך.

      ד"א האם אתה בודק בכלל שגיאות של מסד הנתונים כאשר אתה מבצע פעולות ?

      כלומר יש כאן הרבה מאוד דברים שצריך לבדוק. זו לא פרנויה, אלא זה מה שנדרש ממך. אבל הרבה מאוד אנשים מתעלמים מהדברים האלו בכלל, ויש עם זה בעיות מאוד חמורות.

כתיבת תגובה

הזינו את פרטיכם בטופס, או לחצו על אחד מהאייקונים כדי להשתמש בחשבון קיים:

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s