SQL Injection

‏ • 26 במאי, 2004

מהו SQL Injection?

SQL Injection זהו מצב בו משתמש מצליח להשחיל שאילתת SQL לתוך הקוד.
SQL Injection קורה בדר"כ כאשר משתמש שולח טופס ((form, או פרמטרים ב-QueryString
לדוגמה, נניח ויש לנו טופס התחברות:
user:
pass:


המשתמש מזין נתונים. עוברים ל:









1
2
3
4
5
6  








<%
sql="select usern, pass from Users "
sql=sql & "Where Username = '" & user & "' AND pass = '" & pass "'"
rs.open sql,conn
if not rs.EOF then ' YouAreConnected
%>


נניח המשתמש מקליד את הנתונים הבאים:
user: kid0
pass: 1234


אז הכל יעבוד כשורה, הקוד יבדוק האם שם המשתמש והסיסמה מתאימים זה לזה, אם כן יאשר, אם לא, לא יאשר. הכל טוב ויפה.
אך אם המשתמש מקליד את הפרטים הבאים
user: kid0
pass: ' OR 10=10


אזי השאילתה שלנו תיראה כך:









1
2
3  








select usern, pass
from Users
Where Username = 'kid0' AND pass = " OR 10=10


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

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

S.O.S – מה עושים?

יש לנו 3 דרכים לפתור את הבעיה:

  1. לבדוק את הפרטים שאנו מקבלים ולגלות בהם תווים אסורים ( ', –), ובנוסף לתת רשימה של תווים מותרים. דרך זו לא תמיד טובה, כי לפעמים אנחנו כן רוצים לאפשר תווים כאלו בתוך הטקסט
  2. לבצע החלפה של התווים הבעיתיים בצורה שלא תשאיר אפשרות להזרקת SQL
  3. שימוש ב-Stored Procedures המקבלות פרמטרים, ועבודה עם האובייקט Command. דרך זו היא המומלצת ביותר.

שיטה מס' 1 – סינון תווים בעייתיים:

בדיקת התווים הבעייתיים:









1
2
3
4
5
6
7
8
9
10  








<%
text = "dude, where is my car?"
forbidden = array("'", "–")
for i = LBound(forbidden) to UBound(forbidden)
      if (inSTR(1,text,forbidden(i)) <> 0) then
          badtext = "yes"
        Exit for
    end if
Next
%>


נסביר שורה שורה

  1. מגדירים מערך של תווים אסורים.
  2. יוצרים לולאה שתעבור על כל הערכים במערך
  3. במידה ואחד התווים האסורים קיים במערך אז פונקציית inSTR תיהיה שונה מ0.
  4. אם ישנם תווים אסורים, נותנים למשתנה badtext את הערך "yes"
  5. שימוש ב-Exit For כדי לצאת מהלולאה
  6. סגירת if
  7. במידה ולא נמצא תו אסור בערך הנתון במערך, ממשיכים לעבור על המערך.
כל מה שנשאר לכם הוא לבדוק אם המשתנה badtext שווה ל ""yes ולפעול בהתאם.

בדיקת התווים המותרים:









1
2
3
4
5
6
7
8
9
10  








<%
acc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:/.קראטוןםפשדגכעיחלךףזסבהנמצתץ"
for q = 1 to Len(text)
    c = mid(text,q,1)
    if(inSTR(acc,c) = 0) then
        badtext = "yes"
        Exit For
    end if
Next
%>


גם פה אסביר שורה שורה:

  1. נותנים רשימה של תווים מותרים
  2. יוצרים לולאה שעוברת מ1 עד סוף הstring במשתנה text
  3. מכניסים לתוך משתנה c תו מהstring
  4. בדיקה, אם התו c לא נמצא ברשימת התווים המותרים הפונקציה inSTR תחזיר 0
  5. הבנתם נו 🙂
  6. שימוש ב-Exit For כדי לצאת מהלולאה
  7. סגירת if
  8. אם התו קיים בתווים האסורים, ממשיכים לעבור על הטקסט.

שיטה מס' 2 – החלפת תווים בעייתיים:

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









1
2
3
4
5
6  








<%
UserName=Replace(Request("UserName"),"'",""")
Password=Replace(Request("Password"),"'",""")
SQL="select usern, pass from Users Where "
SQL = SQL & "Username = '" & UserName & "' AND pass = '" & Password "'"
%>


בצורה הזו לא ניתן יהיה "לשבור" את השאילתה.

שיטה מס' 3 – שימוש באובייקט Command

ניצור בבסיס הנתונים Stored Procedure המקבלת פרמטרים (לכל סוג בסיס נתונים יש את הסינטקס שלו. על יצירת SP באקסס ניתן לקרוא פה )

לאחר שיצרנו אותה, נשתמש באובייקט Command בצורה הזו:









1
2
3
4
5
6
7
8
9
10  








<%
Set oCmd = Server.CreateObject("ADODB.Command")
oCmd.ActiveConnection = oCon
oCmd.CommandText = "aSp_Login"
oCmd.CommandType = 4
oCmd.Parameters.Append oCmd.CreateParameter("@sLogin", 200, 1, 50, Request("UserName"))
oCmd.Parameters.Append oCmd.CreateParameter("@sPass", 200, 1, 50, Request("Password"))
Set rs = oCmd.Execute
Set oCmd = Nothing
%>


וזו תהיה הדרך הבטוחה ביותר.

בנוסף – יש להקפיד על כמה כללים:


  • תמיד לבצע בדיקות קלט בצד השרת, בנוסף לצד הלקוח, ולוודא שסוג הנתונים שקיבלתם הוא בדיוק מה שציפיתם לקבל
  • יש להשתדל עד כמה שאפשר לא להעביר מחרוזות ב-QueryString. להעביר ערכים מספריים בלבד.
בהצלחה!

תגיות: , , ,

תגובות בפייסבוק