מהו injection SQL ?
אם אתה מעצב אתר ברשת או שכבר יש לך אתר ברשת , בודאי יטרידו אותך התקפות אפשריות מצד משתמשים נוכלים. כמעט תמיד מפתחי האתרים מתמקדים בנושאי הביטחון כאשר הם בוחרים את מערכת ההפעלה ושרת ה- WEB עליהם ירוץ האתר, אך לא רק נושאים אלו צריכים לקחת בחשבון כאשר מגנים על האתר, הקוד הנפוץ המשמש לאתרי רשת מבוססי מידע מכיל בד"כ חורים אשר לא נופלים מחומרתם מהחורים אשר עלולים להתגלות בשרת ה- WEB.
ניצול לרעה של חור בקוד מעצב האתר נקרא SQL injection attack.
SQL injection היא טכניקה המאפשרת לתוקף להריץ פקודות SQL לא מורשות, ע"י ניצול נתוני קלט אשר תקינותם לא נבדקת ביישומי רשת הבונים שאילתות SQL דינאמיות.
להלן דוגמא נפוצה לכך:
טופס משמש לקליטת שם משתמש וסיסמה של מבקר באתר על מנת לאפשר גישה לדפי מידע מסוימים, הטופס מעביר את הנתונים שהתקבלו ל-ASP script לעיבוד הנתונים.
Script העיבוד בונה שאילתת SQL מהקלט על מנת להחליט אם שם המשתמש והסיסמה מתאימים ומאפשרים גישה למידע.
בתרחיש כזה, ניתן לבנות שני דפים , דף HTML להתחברות למערכת (login) ודף ASP אשר מבצע את וידוא אמיתות הנתונים (כלומר בדוגמא שלנו מחפש את שם המשתמש והסיסמה שהקיש במסד-הנתונים) .
קוד של שני דפים אלו יכול להראות כך:
Login.htm
קוד:
<form action="ExecLogin.asp" method="post">
Username: <input type="text" name="txtUsername"><br>
Password: <input type="password" name="txtPassword"><br>
<input type="submit">
</form>
ExecLogin.asp
קוד:
<%
Dim p_strUsername, p_strPassword, objRS, strSQL
p_strUsername = Request.Form("txtUsername")
p_strPassword = Request.Form("txtPassword")
strSQL = "SELECT * FROM tblUsers " & _
"WHERE Username=’" & p_strUsername & _
"’ and Password=’" & p_strPassword & "’"
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open strSQL, "DSN=..."
If (objRS.EOF) Then
Response.Write "Invalid login."
Else
Response.Write "You are logged in as " & objRS("Username")
End If
Set objRS = Nothing
%>
במבט ראשון , לא נראה שהקוד ב- ExecLogin.asp מכיל חורי אבטחה כלשהם. המשתמש אינו יכול להתחבר למערכת ללא שם משתמש וסיסמה מתאימים.
אולם, קוד זה אינו מוגן, והוא מתאים בדיוק ל- SQL injection attack.
למעשה הפגיעות של הקוד נובעת מכך ששאילתת ה- SQL נבנית ישירות מקלט המשתמש , דבר המאפשר לתוקף לקבוע את תוכן השאילתה שתבוצע.
דוגמא לפגיעות זו תהיה אם המשתמש יזין את המחרוזת הבאה לתוך שדה שם המשתמש\סיסמה : ’ or ’’=’ .
השאילתה שתבוצע תהיה אם כן :
SELECT * FROM tblUsers WHERE Username=’’ or ’’=’’ and Password = ’’ or ’’=’’
שאילתה זו תחזיר את כל הרשומות מהטבלה tblUsers וה- ASP script יחבר את התוקף למערכת בתור המשתמש אשר מופיע ברשומה הראשונה שבטבלה זו.
סוג נוסף של SQL injection stack מתקיים כאשר מקבלים מחרוזת כפרמטר המשמש להפקת דפי רשת דינאמיים.
להלן דוגמא לדף ASP אשר מקבל ID מהמחרוזת ומפיק באופן דינאמי את תוכן הדף בהתבסס על ה- ID.
קוד:
<%
Dim p_lngID, objRS, strSQL
p_lngID = Request("ID")
strSQL = "SELECT * FROM tblArticles WHERE ID=" & p_lngID
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open strSQL, "DSN=..."
If (Not objRS.EOF) Then Response.Write objRS("ArticleContent")
Set objRS = Nothing
%>
בנסיבות רגילות script זה היה מציג את תוכן הכתבה אשר ה- ID הועבר ע"י המחרוזת.
לדוגמא הדף יכול להיקרא:
http://www.example.com/article.asp?ID=1055 , ולכן יוצג התוכן של כתבה 1055.
כמו בדוגמא של ההתחברות למערכת שראינו לעיל , קוד זה חושף את עצמו ל – SQL injection attack, משתמש עוין יכול להחליף ID לא מזיק של כתבה בפקודת SQL מזיקה ע"י כך שישלח ל- ID מלל כמו : 0 or 1=1 , כלומר :
or 1=1 http://www.example.com/article.asp?ID=0.
שאילתת SQL זו תחזיר את כל הכתבות מהטבלה, מכיוון שהיא תראה כך:
קוד:
SELECT * FROM tblArticles WHERE ID=0 or 1=1
כמובן שדוגמא זו אינה נראית מסוכנת במיוחד, אבל התוקף יוכל אז לתמרן את היישום בצורה שתפגע בו באופן קטלני, ע"י החדרת פקודות הרסניות , כמו משפטי DELETE.
כל זה יכול להתבצע ע"י תמרון פשוט של המחרוזת המשמשת לשאילתה !
לדוגמא:
כל אחד יכול לקרוא לדף עם מחרוזת השאילתה הבאה:
http://www.exemple.com/Article.asp?ID=1055; DELETE FROM tblArticles
ההשלכות של SQL injection
ההשלכות המלאות של SQL injection תלויות בסביבה ובתצורה שבה עובדים.
לדוגמא, אם הקישור למסד הנתונים מתבצע בהרשאות של DBO (Data Base Operator) ניתן יהיה לבצע פעולות רבות במסד הנתונים, כגון: מחיקת כל הטבלאות במסד-הנתונים , יצירת טבלאות חדשות וכו’.
אם הקישור למסד-הנתונים הוא במושגים של SA (System Administrator), ניתן יהיה לשלוט בכל שרת ה-SQL, דבר אשר יאפשר בתצורה המתאימה גם ליצור חשבונות משתמשים אשר יוכלו לשלוט בשרת ה- Windows אשר משמש כ- host למסד-הנתונים.
הגנת יישומים מפני SQL injection
הדבר הראשון אותו יש לעשותה הוא להגן על שאילתות ה- SQL ע"י מימוש טכניקות "ניקוי" לכל הקלט אשר מתקבל מכל- object ASP request (Request, Request.QueryString, Request.Form, Request.Cookies ו- Request.ServerVariables).
טכניקות ה"ניקוי" מגוונות, ותלויות ב- DBMS (Data Base Management System) בו משתמשים, טכניקות לדוגמא ל- MS SQL Server יוצגו בהמשך.
בדוגמא של מסך הכניסה למערכת (login Page) ה- ASP script ציפה ששני משתנים (txtUserName ו- txtPassword) מסוג מחרוזת יועברו אליו, כשגרש יחיד ( ’ ) משולב במחרוזת , הוא מאפשר למשתמש לשלוט בפקודה שמתבצעת. כדי להתגבר על איום SQL injection מסוג זה, נמנע הופעת גרש יחיד במחרוזת הקלט ע"י שימוש בפונקצית Replace כך:
p_strUsername = Replace(Request.Form("txtUsername"), "’", "’’")
p_strPassword = Replace(Request.Form("txtPassword"), "’", "’’")
כלומר נחליף כל גרש יחיד בזוג גרשיים (למעשה הייצוג הטקסטואלי של גרש יחיד ב- SQL נכתב כשני גרשיים, כמו שבשפת C כדי לכתוב "\" במחרוזת, נרשום "\\").
בדוגמא השנייה שראינו , ה- script ציפה למשתנה (ID) מסוג מספר גדול (Long) , פקודת SQL לא מורשית יכולה להתבצע ע"י שרשור קוד SQL לפרמטר ה- ID . כדי להתגבר על איום מסוג זה , פשוט נגביל את הקלט לסוג מספר גדול ע"י שימוש ב- CLng כך:
p_lngID = CLng(Request("ID"))
אם המשתמש ינסה להעביר מחרוזת כפרמטר , פונקצית CLng תגרום לתקלה.
בכדי להפחית סיכונים נוספים מסוג injection SQL, יש לדאוג להסיר כל מידע טכני מהודעות השגיאה המוצגות למשתמש. המידע שבהודעות השגיאה חושף לעיתים קרובות כיצד הקוד בנוי ומספק לתוקף נתונים לתמרון היישום.
לבסוף, בכדי להגביל את טווח הפגיעה של SQL injection attack, יש להגביל את ההרשאות לחשבון מסד הנתונים בו משתמש יישום ה- Web. היישום בד"כ אינו צריך הרשאות DBA או SA.
ככל שניתנות פחות הרשאות למסד הנתונים הסיכון לפגיעה בנתונים קטן משמעותית.
מומלץ ליצור חשבונות נפרדים לכל רכיב ביישום המתקשר למסד-הנתונים בכדי לבודד את המפגעים האפשריים. לדוגמא, ממשק התצוגה של אתר ברשת דורש הגבלות רבות (המתבטאות בהרשאות נמוכות) יותר בגישה למסד-הנתונים מאשר מערכת פנימית לניהול תכני האתר.