SQL Injection (SQLi)¶
מבוא¶
חולשת SQL Injection (SQLi) היא אחת הפגיעויות החמורות ביותר בתחום אבטחת המידע. זוהי טכניקה שבה תוקף מזריק שאילתות SQL זדוניות למסד הנתונים דרך קלט משתמש לא מבוקר. מתקפה זו מאפשרת לתוקף לקרוא, לשנות או אף למחוק נתונים ממסד הנתונים של האתר.
כיצד פועלת מתקפת SQLi?¶
כאשר מערכת מקבלת קלט מהמשתמש ומכניסה אותו ישירות לשאילתת SQL ללא סינון מתאים, תוקף יכול להזריק קוד SQL זדוני במקום הקלט הצפוי. כך ניתן לשנות את התנהגות השאילתה ולבצע פעולות בלתי מורשות במסד הנתונים.
דוגמה לקוד PHP פגיע¶
התחברות ללא סינון קלט¶
<?php
$conn = new mysqli("localhost", "root", "", "users_db");
$username = $_GET['username'];
$password = $_GET['password'];
$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = $conn->query($query);
if ($result->num_rows > 0) {
echo "Login successful!";
} else {
echo "Invalid credentials.";
}
?>
מתקפה אפשרית¶
אם התוקף מכניס את הערך הבא בשדה שם המשתמש:
השאילתה תהפוך ל:
מכיוון ש--- מסמן הערה ב-SQL, חלק מהשאילתה מתבטל, והכניסה תתבצע ללא צורך בסיסמה.
והשאילתה
כך שאם יש משתמש בשם admin באתר, נוכל פשוט להתלגן.
בנוסף נוכל גם להכניס payload שנראה כך:
כך שהשאילתה תראה כך:
כך שזה יריץ את השאילתה הבאה:
ובגלל שבסוף השיאלתה יש or 1=1 וזה תמיד יחזיר אמת, נקבל את כל הdatabase ונקבל Login sucessful.
כיצד להגן על המערכת?¶
✅ שימוש ב-Prepared Statements¶
<?php
$conn = new mysqli("localhost", "root", "", "users_db");
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $username, $password);
$username = $_GET['username'];
$password = $_GET['password'];
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
echo "Login successful!";
} else {
echo "Invalid credentials.";
}
?>
מדוע זה בטוח?
-
השאילתה אינה נבנית באמצעות מחרוזת אלא משתמשת במשתנים מאובטחים.
-
המערכת מונעת הכנסת קוד SQL זדוני על ידי Escape אוטומטי של הקלט.