SQL Injection چیست؟ مثال ساده و راه جلوگیری برای برنامهنویسها
SQL Injection یا تزریق SQL یکی از قدیمیترین آسیبپذیریهای وب است و هنوز هم در فهرست مشکلات رایج امنیتی دیده میشود. خوشبختانه جلوگیری از آن، اگر روش درست را بدانید، ساده است. این نوشته آموزشی و برای برنامهنویسهایی است که میخواهند کد امن بنویسند.
مسئله چیست؟
برنامه برای خواندن اطلاعات از دیتابیس یک دستور SQL میسازد. اگر ورودی کاربر را مستقیم به رشتهی دستور بچسباند، کاربر میتواند خودِ ساختار دستور را عوض کند.
مثال اشتباه (شبهکد):
// خطرناک: ورودی مستقیم داخل رشته
const q = "SELECT * FROM users WHERE username = '" + username + "'";
اگر کاربر بهجای نام، متنی بنویسد که علامت نقلقول و دستورهای SQL دارد، دیتابیس آن را بخشی از دستور میپندارد و ممکن است دادههایی را برگرداند که نباید.
چه آسیبی میزند؟
بسته به پیکربندی: خواندن اطلاعات غیرمجاز (مثلاً کاربران و رمزها)، دور زدن لاگین، تغییر یا حذف داده. به همین دلیل جدی گرفته میشود.
راه اصلی جلوگیری: پرسوجوی پارامتری
دستور و داده را جدا بفرستید. دیتابیس مقدار را هرگز بهعنوان بخشی از دستور تفسیر نمیکند.
// امن: placeholder و پارامتر جدا
const q = "SELECT * FROM users WHERE username = ?";
db.query(q, [username]);
اگر از ORM مثل Prisma، Sequelize یا SQLAlchemy استفاده میکنید، متدهای معمولیشان بهصورت پیشفرض پارامتریاند. خطر وقتی برمیگردد که برای یک مورد خاص دستور خام (raw query) بسازید و ورودی را به آن بچسبانید؛ مثلاً در Prisma متدهای $queryRawUnsafe با ورودی کاربر.
لایههای دیگر دفاع
- اعتبارسنجی ورودی در سرور (نوع، طول، قالب). کمک میکند، ولی جایگزین پارامتریکردن نیست.
- کمترین دسترسی: کاربر دیتابیسی که برنامه استفاده میکند فقط مجوزهای لازم را داشته باشد؛ نه مالک کل دیتابیس.
- پیام خطای عمومی: جزئیات خطای دیتابیس را به کاربر نشان ندهید.
- هشکردن رمزها: حتی اگر دادهها لو بروند، رمزها ساده نیستند (bcrypt یا Argon2).
- تست امنیتی: ابزارها و اسکنرها فایلها و پیکربندیهای مشکلدار را پیدا میکنند؛ برای نمونه نگاهی به چطور یک اسکنر کار میکند بیندازید. فقط روی سیستم خودتان یا با مجوز.
چکلیست سریع
- هیچ جا ورودی کاربر مستقیم به رشتهی SQL چسبانده نمیشود.
- در ORM، هر
raw queryبا دقت و پارامتر نوشته میشود. - حساب دیتابیس برنامه کمترین مجوز را دارد.
- خطاها به کاربر جزئیات نمیدهند.
- ورودیها اعتبارسنجی میشوند.
سوالات رایج
آیا ORM کاملاً جلوی SQL Injection را میگیرد؟ برای استفادهی معمولی بله، ولی با دستورهای خام و ورودی چسباندهشده نه.
آیا فقط پایگاههای دادهی SQL تحت تاثیرند؟ مشکل «تزریق» کلیتر است و در پایگاههای NoSQL و دستورهای سیستمعامل هم شبیه آن وجود دارد؛ اصل یکی است: داده را با دستور قاطی نکنید.