הזרקת SQL
הזרקת SQL (באנגלית: SQL Injection) היא שיטה לניצול פרצת אבטחה בתוכנית מחשב בעזרת פניה אל מסד הנתונים. השם נובע מכך שהמשתמש מכניס קוד SQL לשדה קלט אליו אמורים היו להיכנס נתונים תמימים. באופן זה יכול משתמש זדוני לחרוג לחלוטין מן התבנית המקורית של השאילתה, ולגרום לה לבצע פעולה שונה מזו שיועדה לה במקור. הזרקת SQL היא מקרה פרטי של קבוצה רחבה של פרצות אבטחה הנקראות הזרקות קוד, שמתרחשות כאשר תוכנה כלשהי יוצרת קוד בזמן ריצה על־פי הקלט ובלי לבדוק את תוכן הקלט תחילה.
כל תוכנית שבונה שאילתות SQL תוך שילוב של נתונים מן המשתמש, עלולה להיות פגיעה להזרקה, עלולה לחשוף נתונים שהמתכנת חשב שלא יוכלו להחשף ועלולה לגרום נזק לנתונים עצמם ומכיוון שכך, היא עלולה להיות פגיעה ללוחמת סייבר.
דוגמה לפרצה
בדוגמה הבאה, הנתונה ב־ASP, ביקש המתכנת לקלוט מהמשתמש את סיסמת הגישה שלו לאתר אינטרנט מאובטח, לבדוק את תקינותה כנגד מסד הנתונים ולאשר את הגישה אם הסיסמה אכן קיימת. הקוד (הפגיע לפריצה) הבונה את שאילתת ה-SQL נראה כך:
SQL = "SELECT * FROM users WHERE password='" & Request("password") & "'"
כאשר האובייקט Request משמש לקבלת נתונים מטפסים. כעת, השימוש התקין שראה המתכנת לנגד עינו הוא הכנסת סיסמה, למשל 1234, שתייצר את שאילתת ה-SQL הבאה:
SQL = "SELECT * FROM users WHERE password='1234'"
ובהנחה שאין בטבלת users רשומה שבה העמודה password מכילה את הערך '1234', לא נוכל לקבל גישה.
אך על ידי הזרקת SQL יכול משתמש זדוני להכניס את הקלט הבא:
' OR 'a'='a
שייצר את שאילתת ה-SQL הבאה:
SQL = "SELECT * FROM users WHERE password='' OR 'a'='a'"
על ידי הכנסת "נתון" שהוא למעשה בחלקו נתון ובחלקו קוד מבני של השאילתה, שינה המשתמש את השאילתה לכזו שמחזירה את כל הרשומות בטבלה, משום שהערך 'a' תמיד שווה לעצמו. קוד התוכנית שפועל אחרי הרצת השאילתה יניח שמאחר ותוצאת השאילתה אינה ריקה, יש לאפשר גישה מלאה למשתמש, אף שבפועל אין לו סיסמה תקפה. לפורץ כעת יש גישה כאילו הכניס סיסמה.
פתרון
על מנת להיות בטוחים שקוד לא יהיה חשוף להזרקה, אפשר לנקוט באחת משתי הגישות הבאות (ורצוי בשתיהן):
בדיקת תקינות הקלט
על המתכנת לבדוק את כל הנתונים המגיעים מן המשתמש:
- בשדות טקסט יש לבדוק שהערכים בשדות לא מכילים תווים מיוחדים מסוימים - בדוגמה למעלה מדובר בגרש (
'
) - ניתן להשתמש בשגרות של שפת התכנות של מסד הנתונים, כך שניסיון להחדיר את הטקסט יגרום לשגיאה של המערכת במקום לחדירה. בשפה העברית עדיף לבצע החלפה (אם מדובר בשדה שאמור לקלוט מילים), שכן התו גרש נמצא בשימוש יומיומי.
- נתונים מספריים יש לבדוק כדי לאשר שהם מקבלים ערך מספרי בלבד.
- נתונים הנשמרים על עוגייה ניתן לערוך בצד המשתמש ולכן יש לבדוק גם אותם.
שימוש במבנה קשיח יותר של שאילתה
שפות התכנות השונות מציעות פתרון עדיף לבעיה, על ידי כך שהמתכנת יכול להכין שאילתה מובנית ולשים "שומרי מקום" (placeholder) במקומות שאליהן יוכנס אחר כך הנתון הנקלט מהמשתמש. לדוגמה במקום קטע הקוד הבא, הכתוב בשפת JAVA:
Connection con = (acquire Connection)
Statement stmt = con.createStatement();
ResultSet rset = stmt.executeQuery("SELECT * FROM users WHERE name = '" + userName + "';");
ניתן לכתוב כך:
Connection con = (acquire Connection)
PreparedStatement pstmt = con.prepareStatement("SELECT * FROM users WHERE name = ?");
pstmt.setString(1, userName);
ResultSet rset = pstmt.executeQuery();
באופן זה תשתית התוכנה עצמה מוודאת שמבנה השאילתה אינו משתנה על ידי הנתון. אם ינסה אותו משתמש זדוני את אותה שיטה המודגמת למעלה, תיווצר חריגה בעת הרצת השאילתה, שכן כבילת (binding) הנתון לשומר המקום תיכשל.
ראו גם
קישורים חיצוניים
- מדריך בדיקות קלט ושיטות התגוננות מפני SQL Injection בעברית
- מדריך SQL Injection בעברית
- How To: Protect From Injection Attacks in ASP.NET
33962252הזרקת SQL