ביצוע Binding שמי במסדי נתונים

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

קודם כל מהו bind ? ובכן bind זו דרך להוסיף תוכן חיצוני לשאילתות שלנו, כאשר מסד הנתונים יודע להבין שמדובר בערך חיצוני ולכן הוא מבצע פעולת escaping על המידע בשביל שלא יתרחש sql inection.

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

במרבית מסדי הנתונים יש תמיכה בלפחות סוג אחד של bind, אשר נקרא anonymous binding.  הרעיון שלו הוא לקבל ערך במקום שבו הוא הוגדר. עם הערך הזה אנחנו יכולים תיאורטית לעבוד רק במקום אחד (בו הכרזנו על השימוש בו). בעיה עם הbind האנונימי היא הקושי הגדול של דיבוג המידע, קשה לנו לדעת לאן המידע שהזנו הלך בצורה ישירה. השימוש ב bind אנונימי נראה כך:

select name from users where id=?

המיקום של ה binding הוא בסימן שאלה. הסימן שאלה מוחלף בתוכן שלנו אחרי שעבר escaping. התחביר עצמו של סימן השאלה זהה בכל מסדי הנתונים שאני מכיר.

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

select name from users where id=:id

מסד הנתונים MS SQL Server מגדיר אותו מעט אחרת. מה ששונה כאן הוא שיש לנו משתנה בשם id (המתחיל בנקודותיים). כמו שניתן להבין היות ואנחנו לא מחליפים רק מקום בתוכן, אלא ממש משתמשים בשם משתנה, אפשר לקחת את id: לעוד מקומות בשאילתא בשביל להשתמש בה, וכך אנחנו יכולים למשל להשיג את עיקרון ה dry גם עם binding.

ב MS SQL Server יש הגדרה שונה ל named binding (עד כמה שאני יודע, אין לי ניסיון צד ראשון עם המסד נתונים, רק קריאה של קוד שאחרים כתבו):

select name from users where id=@id

הסימן של שטרודל לפני השם id היא הדרך להגדיר משתנה ב MS SQL Server וכך ניתן לתת לו פרמטרים בעצם.

ישנם עוד כמה סוגי binding שונים, כדוגמת index based אשר לא נמצאים בשימוש רחב ומאוד מזכירים את anonymous ולכן מעדיפים להשתמש ב anonymous במקום.

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

3 מחשבות על “ביצוע Binding שמי במסדי נתונים

  1. משה

    תודה עידו, פוסט מעניין.
    אני מוכרח להוסיף הסבר מעט יותר מעמיק על מה בעצם קורה כשעושים כמשתמשים ב bind: ראשית, מסד הנתונים מקמפל את השאילתא, קרי, הופך אותה לקוד בר ביצוע, ומשאיר לעצמו מקום לשים את הערכים של ה bind. משמעות הדבר היא שבשלב זה, כבר נבנה execution plan לשאילתא, ומסד הנתונים יודע בדיוק מה עליו לבצע, רק בלי הפרמטרים. לאחר מכן, בזמן הריצה, נשתל ערך ה bind והשאילתא רצה. הדבר מוביל, כמובן, לשיפור בביצועים, שכן שאילתא מתקמפלת פעם אחת, אך יכולה להתבצע מספר רב של פעמים, עם פרמטרים שונים. שנית, גם אם תנסה לשתול פרמטרים בעייתיים בניסיון לבצע sql injection, הרי שתיכשל, משום שמסד הנתונים כבר יודע מה השאילתא שעליו לבצע, והוא לא יקמפל את התוכן של השאילתא החדשה (למשל, אם שתלת שליפה נוספת או שינית את תחביר השליפה). ניתן לדמיין את זה כמו ביצוע של שפת סקריפט, שנורא פשוט לערוך באמצעות עורך טקסט, לבין ביצוע של קוד מקומפל, שאין לך ממש סיכוי לערוך בקלות. הן מבחינת אבטחה והן מבחינת ביצועים.

  2. Shai

    עידו, הבלגן אצלך חוגג.

    כשעושים binding כמו שצריך, אז מתקיים מה שכתבת: "ניקח את המידע … ונגרום לו להיות לא מאיים אלא חלק מהמידע שלנו". כלומר, נפריד מבנית בין נתונים לבין קוד SQL. כשעושים את זה, אין שום צורך ב-escaping, ובאמת אין escaping. בשום שלב, לא מתקיימת פקודת SQL שהתוכן "שתול" בה. ההבדל הוא כמו ההבדל בין מאקרו לפונקציה ב-C: בפונקציה (ו-binding), הקוד (C או SQL) מעובד לפורמט ביצועי בלי קשר לערכי הפרמטרים; רק במאקרו (ושתילה, עם או בלי escaping), ערכי הפרמטרים מופיעים בתוך הקוד ועלולים לשבש אותו.

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

    נתקלתי, אמנם, בתוכנת מסד נתונים אחת, שבה המימוש של ממשק binding היה ע"י ביצוע escaping ושתילת המחרוזת של הפרמטר בתוך הפקודה, בספריית הלקוח, לפני שליחת ה-SQL לשרת. פוסטים קודמים שלך יעזרו לך לנחש איזהו הדרעק. אצל רובם, זה פשוט לא עובד ככה, ואני מקווה שגם ההוא כבר התבגר מאז.

  3. ik_5 מאת

    תודה על ההרחבה של שניכם.

    ניסיתי לפשט מאוד את הנושא ולא להיכנס למבנה של הידור שאילתות, אופטימיזציה וכו'.
    הרעיון היה שאנשים יבינו מה זה bind ולא אץ היתרונות/חסרונות שלו.

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

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

כתיבת תגובה

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

הלוגו של WordPress.com

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

תמונת Twitter

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

תמונת Facebook

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

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

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

מתחבר ל-%s