SQL Injection

در SQL وقتی ورودی‌های کاربر به‌درستی کنترل نشن، ممکنه مهاجم با وارد کردن دادهٔ دست‌کاری‌شده دستورهای SQL دلخواه رو اجرا کنه — به این حمله می‌گیم SQL Injection. این آسیب‌پذیری می‌تونه منجر به افشای داده‌ها، تغییر یا حذف اطلاعات و حتی گرفتن کنترل سرور بشه.

🔹 چطور اتفاق میفته؟

وقتی برنامه ورودی کاربر رو مستقیم داخل یک رشتهٔ SQL قرار می‌ده (بدون پارامتریک‌سازی یا پاک‌سازی)، مهاجم می‌تونه با وارد کردن متن خاص منطق کوئری رو تغییر بده.

مثال ناامن (پایتون/پتکی):

-- فرض: username و password از فرم گرفته میشه query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";

اگر attacker مقدار username =  OR '1'='1 وارد کنه، کوئری تبدیل میشه به:

SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '...';

که شرط همیشه true میشه و مهاجم ممکنه به سیستم وارد بشه.

🔹 انواع متداول SQL Injection

  • In-band (مثلاً UNION-based, Error-based): مهاجم مستقیم نتیجه یا خطاها رو می‌بینه و داده‌ها رو استخراج می‌کنه.

  • Blind SQL Injection: خروجی مستقیم نیست؛ مهاجم با پرس‌وجوهای شرطی یا time-based اطلاعات رو تدریجی بدست میاره.

  • Out-of-band: وقتی داده‌ها از مسیر دیگری مثل DNS یا HTTP callback استخراج میشن (کمتر رایج، اما خطرناک).

🔹 نمونه‌های واقعی حمله (خلاصه)

  • دور زدن احراز هویت با ' OR '1'='1

  • استخراج داده با UNION SELECT

  • اجرای دستورات تغییر ساختار یا خواندن فایل‌ها (در صورتی که سطح دسترسی DBMS اجازه بده)

🔹 بهترین روش‌های جلوگیری (Best Practices)

  1. همیشه از پارامترایزد کوئری‌ها (Prepared Statements / Parameterized Queries) استفاده کن.

    • مثال (PHP PDO):

      $stmt = $pdo->prepare("SELECT * FROM users WHERE username = :u AND password = :p"); $stmt->execute([':u' => $username, ':p' => $password]);
  2. از ORM یا لایهٔ دسترسی به داده که پارامتریک‌سازی رو تضمین می‌کنه، استفاده کن.

  3. ورودی‌ها را اعتبارسنجی و محدود کن (whitelist): طول، نوع، الگو (مثلاً ایمیل)، نه صرفاً پاک‌سازی.

  4. از least privilege پیروی کن: حساب DB برنامه نباید دسترسی‌های غیرضروری (مثل DROP یا ADMIN) داشته باشه.

  5. خطاهای دیتابیس را به کاربر نمایش نده؛ لاگ کن ولی پیام عمومی نشون بده.

  6. از stored procedures با پارامتر امن استفاده کن (اما اگر داخل stored procedure رشته‌سازی انجام بشه، امن نیست).

  7. Web Application Firewall (WAF) می‌تونه لایهٔ دفاعی اضافه فراهم کنه — مکمل نه جایگزین.

  8. پسوردها و داده‌های حساس را هش/رمزنگاری کن (bcrypt/Argon2).

  9. تست امنیتی منظم (SAST, DAST) و penetration testing انجام بده.

🔹 مثال ایمن در SQL Server با sp_executesql (پارامترایزه):

DECLARE @sql NVARCHAR(4000) = N'SELECT * FROM Users WHERE Username = @u'; EXEC sp_executesql @sql, N'@u NVARCHAR(50)', @u = @username;

🔹 نکات تکمیلی

  • برای الگوهای LIKE هم پارامتریک باش؛ از concat کردن مستقیم رشته با % خودداری کن یا از پارامترهای امن استفاده کن.

  • هرگز جزئیات ساختار DB (مثل نام جدول‌ها، ستون‌ها یا مسیر فایل‌ها) را در پیام خطا نمایش نده.

  • لاگ‌برداری از تلاش‌های ناموفق و الگوهای مشکوک می‌تونه حملات Blind را زودتر کشف کنه.

خلاصه:
SQL Injection نتیجهٔ نادیده گرفتن پارامتریک‌سازی و اعتبارسنجی ورودی‌هاست. بهترین دفاع استفادهٔ همیشگی از prepared statements، اعتبارسنجی ورودی‌ها، حداقل مجوزها و تست/مانیتورینگ دوره‌ایه.