فرانت‌اند

آشنایی با SQL Injection و روش‌های جلوگیری

SQL Injection چطور کار می‌کنه، چرا خطرناکه، و چرا Prepared Statement تنها راه دفاع قابل‌اعتماده — با مرجع رسمی OWASP.

عارف بوساک
عارف بوساکنویسنده
۱۴۰۳/۰۳/۱۶۳ دقیقه۰ بازدید
آشنایی با SQL Injection و روش‌های جلوگیری

SQL Injection چیست؟

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

مشکل اصلی اینجاست که SQL هیچ مرز مشخصی بین «دستور» و «داده» قائل نیست. اگر ورودی فرم را مستقیم داخل کوئری بچسبانیم، مثلاً:

SELECT * FROM items WHERE owner = 'user' AND itemname = 'name'

و مهاجم به‌جای name مقدار name' OR 'a'='a را وارد کند، کوئری نهایی این‌طور می‌شود:

SELECT * FROM items WHERE owner = 'user' AND itemname = 'name' OR 'a'='a'

از آنجا که 'a'='a' همیشه درست است، شرط WHERE عملاً بی‌اثر می‌شود و همه‌ی رکوردها برگردانده می‌شوند. نسخه‌های پیشرفته‌تر این حمله می‌توانند با batch کردن چند دستور (مثلاً افزودن ; DELETE FROM items; --) داده‌ها را پاک یا دستکاری کنند.

چرا خطرناکه؟

یک SQL Injection موفق می‌تواند:

  • داده‌های محرمانه (رمز عبور، اطلاعات پرداخت) را لو بدهد
  • رکوردها را تغییر بدهد یا حذف کند
  • احراز هویت را دور بزند
  • در بدترین حالت، به سطح دسترسی ادمین دیتابیس برسد

OWASP این نوع حمله را در دسته‌ی «شدت بالا» طبقه‌بندی می‌کند، چون هم فراوان است و هم تاثیرش مستقیم روی داده‌هاست.

راه‌حل اصلی: Prepared Statements

قابل‌اعتمادترین راه دفاع، جدا کردن کامل «دستور» از «داده» با استفاده از پرس‌وجوهای پارامتری (Parameterized Queries) است. به‌جای چسباندن ورودی کاربر به متن کوئری، مقدار به‌عنوان پارامتر جدا به دیتابیس فرستاده می‌شود و دیتابیس هیچ‌وقت آن را به‌عنوان بخشی از دستور SQL تفسیر نمی‌کند.

اگر از یک ORM مثل Prisma استفاده کنید (دقیقاً مثل همین پروژه)، این محافظت به‌صورت پیش‌فرض فعال است:

await prisma.user.findFirst({
  where: { email: userInput },
});

Prisma در پشت صحنه از پرس‌وجوی پارامتری استفاده می‌کند، پس ورودی کاربر هیچ‌وقت مستقیم داخل متن SQL چسبانده نمی‌شود.

لایه‌های دفاعی مکمل

پرس‌وجوی پارامتری کافی است، ولی این موارد هم دفاع را قوی‌تر می‌کنند:

  • کمترین دسترسی: اکانت دیتابیسی که اپلیکیشن باهاش وصل می‌شود نباید بیشتر از نیازش دسترسی داشته باشد.
  • اعتبارسنجی ورودی: محدود کردن فرمت ورودی یک لایه‌ی دفاعی اضافه است، نه جایگزین پرس‌وجوی پارامتری.
  • Web Application Firewall (WAF): می‌تواند حملات شناخته‌شده را فیلتر کند، ولی قابل دور زدن است و نباید تنها راه دفاع باشد.

جمع‌بندی

SQL Injection یک آسیب‌پذیری کاملاً قابل‌پیشگیری است. اگر همیشه از Prepared Statement یا یک ORM قابل‌اعتماد استفاده کنید و دسترسی دیتابیس را محدود نگه دارید، عملاً این کلاس از حمله را از بین می‌برید.

منبع: OWASP SQL Injection Prevention Cheat Sheet

فرانت‌اند
عارف بوساک
عارف بوساک

طراحی وب، توسعه‌ی بهتر — وب‌سایت‌های سریع، مدرن و نتیجه‌محور.