پرنیا اسحاقی
پرنیا اسحاقی
خواندن ۱۸ دقیقه·۳ سال پیش

حمله SQL Injection چیست و چگونه عمل می‌کند؟

تصویر از سایت geekflare
تصویر از سایت geekflare

این مقاله توضیحات تئوری مختصری راجع به SQL Injection است که حتی کسی که کوچک‌ترین دانسته‌ای راجع به SQL و پایگاه داده ندارد بتواند مطلب را بفهمد. قبل از این‌که بفهمیم SQL Injection چیست بهتر است بدانیم هرکدام از اجزای تشیکل‌دهنده اصطلاحش به چه معناست.

زبان SQL چیست؟

کلمه SQL مخفف شده‌ی Structured Query Language است که تقریبا به «زبان پرسمان سختار یافته» ترجمه می‌شود. این زبان یک زبان استاندارد جهانی است که برای مدیریت و دسترسی به پایگاه‌های داده یا دیتابیس‌ها استفاده می‌شود. چه داده‌های یک وبسایت، چه داده‌های یک اپلیکیشن و چه داده‌های یک بازی باشد، به احتمال زیادی از SQL برای ذخیره کردن و دسترسی به این داده‌ها استفاده می‌کنند. داده‌های درون SQL به صورت جدولی و در tableهای مختلف با ستون‌های مختلف که صفت یا attribute نام دارند، ذخیره می‌شوند که از طریق کلیدهایی با هم ارتباط دارند.

اس‌کیو‌اِل یا سیکوئل؟ اگر با این زبان آشنا باشید احتمالا پیش آمده است که دو نوع مختلف گویش اسمش را شنیده باشید و برایتان سوال پیش بیاید که بالاخره کدام درست است! اولین نسخه‌ی این زبان در دهه هفتاد میلادی به اسم Structured English Query Language یا SEQUEL منتشر شد. اما چون این اسم نام تجاری یک شرکت تولید هواپیما بود مجبور شدند حروف صدادارش را حذف کنند و به SQL تبدیل شد. (و کمی بعدتر English هم از اصطلاح کلی حذف شد) امروزه اکثر منابع رسمی اس‌کیوال را نوع تلفظ درست معرفی می‌کنند اما همچنان میان برنامه‌نویس‌ها سیکوئل رواج دارد و مورد قبول است.

البته برای استفاده از زبان SQL یک RDBMS هم لازم داریم. یعنی چی؟ یعنی Relational Database Management System یا سیستم مدیریت پایگاه‌ داده‌ی رابطه‌ای. به یک RDBMS احتیاج داریم که بتوانیم یک پایگاه داده بسازیم و داده‌های درونش را اضافه و کم کنیم و به طور کلی داده‌ها را راحت‌تر مدیریت کنیم. RDBMSهای مختلفی برای استفاده وجود دارند چندتا از معروف‌ترین‌ها MySQL، MS SQL Server، PostgreSQL و Oracle هستند. زبانی که این RDBSMها استفاده می‌کنند تقریبا شبیه هم هستند اما بعضی جزئیات آن‌ها با هم فرق می‌کند که در حمله‌های SQL Injection از آن‌ها برای حمله‌ی دقیق‌تر استفاده می‌شود.

حمله Injection چیست؟

حمله‌ی Injection یک دسته‌ی گسترده از حمله‌های سایبری است که در آن‌ها اتکر (Attacker) با استفاده از قسمت‌های ورودی کاربر یا هر جای دیگر نرم‌افزار که به درستی توسط برنامه‌نویس محافظت نشده، کد و اطلاعات جدیدی را وارد برنامه می‌کند که مسیر اجرایی آن را تغییر می‌کند. این دسته از حمله‌ها به علت راحتی پیدا کردن و شناسایی آن‌ها به علاوه‌ی قابلیت تخریب و خسارات بالایی که می‌توانند بزنند از خطرناک‌ترین حمله‌ها هستند. با این وجود همچنان هم سهل‌انگاری‌های زیادی در محافظت در مقابل آن‌ها وجود دارد. به طوری که هنوز جز ۱۰ پر ریسک‌ترین مشکلات امنیتی برنامه‌هاست. طبق لیست OWASP که در زیر مشاهده می‌کنید در سال ۲۰۱۷ شماره‌ی یک و در ۲۰۲۱ شماره‌ی ۴ است.

Top 10 Web Application Security Risks
Top 10 Web Application Security Risks

حمله‌ی Injection انواع مختلفی دارد که یکی از معروف‌ترین آن‌ها SQL Injection هست که این مقاله راجع به آن است.

حمله SQL Injection چیست؟

بالاخره رسیدیم به تیتر مقاله! از تعریف اجزای اسمش احتمالا تا الان فهمیدید که قضیه چیست. در این حمله اتکر با استفاده از قسمت‌های ورودی کاربر یا هرجای دیگری که مستقیما با پایگاه داده از طریق زبان SQL ارتباط دارد، دستورات جدیدی را وارد برنامه می‌کند که می‌تواند پایگاه داده‌ی نرم‌افزار را کنترل کند مثلا اطلاعات کاربران را بدزدد یا به طور مخرب‌تر کل پایگاه داده را از بیخ و بن پاک کند! برای درک بهتر این حمله کمی دستورات SQL را و طوری که ممکن است در یک سایت و برنامه از آن استفاده شود را با مثال‌های ساده در پایین توضیح می‌دهیم.

چند مثال

سیکوئل به اندازه زبان‌های برنامه‌نویسی دیگر دستورات خیلی زیادی ندارد چون یک زبان مخصوص پایگاه داده است و فقط برای آن استفاده می‌شود. یکی از پراستفاده‌ترین دستوراتش SELECT است که داده‌های به خصوصی را در پایگاه داده پیدا می‌کند یا به اصطلاح select می‌کند! چیز‌هایی که جلوی SELECT می‌آید در واقع مشخصات داده‌ای است که باید دنبال آن بگردد. این همان کوئری یا پرسمانی است که در کلمه‌ی SQL است. به کد زیر توجه کنید:

SELECT * FROM table_name;

از سمت چپ به راست اول SELECT را داریم که راجع به آن توضیح دادیم. بعد «*» را داریم که در SQL به معنی‌ همه‌چیز است یعنی همه‌ی‌ داده‌ها یا دقیق‌تر در اینجا همه‌ی ستون‌ها یا صفت‌ها. FROM که یعنی «از». table_name که همانطور که واضح است اسم یک جدول در پایگاه داده‌ی ماست و در آخر «;» که به نشانه‌ی اتمام کوئری است. دستورات SQL اکثرا مانند یک جمله‌ی انگلیسی در می‌آیند به همین علت درک آن‌ها بسیار ساده هست. یک نکته هم که احتمالا به آن توجه کردید این است که بر اساس استایل گاید رسمی این زبان دستورات SQL باید با حروف تمام درشت نوشته شوند و هر چیزی به جز دستور با حروف تمام کوچک. این کار برای درک بهتر کوئری‌ها در نگاه اول است اما بدون عمل کردن به آن هم دستورات اجرا می‌شوند. پس به طور خلاصه دستور بالا به این معناست که همه‌ی ستون‌های موجود در جدول یا تیبل table_name برایم بیاور.

قسمت ورود کاربران - Login

حالا بیاید فرض کنیم که یک برنامه‌نویس هستیم و می‌خواهیم موقع ورود کاربران نام کاربری و رمز آن‌ها را با پایگاه داده چک کنیم و اگر موجود بود اجازه‌ی ورود به آن‌ها بدهیم. کدمان ممکن است در php یا هر زبان دیگری باشد اما قسمت سیکوئل آن مثلا را به طور زیر می‌نویسیم:

SELECT * FROM users WHERE username = ' ' AND pass = ' ' ;

دستور WHERE و AND در اینجا اضافه شدند که اولی شرطمان است و دومی به معنی «و». پس به طور کلی این بار کوئری ما این است: «همه‌ی داده‌ها از جدول یوزرز (جدولی که اطلاعات کاربرها در آن ثبت شده) برگردان که در آن‌ها یوزرنیم برابر -جای خالی- و پسوورد برابر -جای خالی- باشد.» که جاهای خالی در کوئری با ورودی کاربر پر می‌شوند. به عبارت دیگر وقتی کاربر اسم و رمز خود را وارد می‌کند در پشت صحنه ورودی‌هایش مستقیم وارد سیکوئل می‌شود (که از همین جا مشکل کد ما پیداست) و اگر اسم و رمزش در پایگاه داده باشد و فقط یک نتیجه از جدول برگردد کاربر می‌تواند وارد اکانتش شود. اما اگر کوئری نتیجه‌ای نداشته باشد یعنی اسم یا رمز یا هر دو اشتباه‌اند و همچین کاربری در پایگاه‌ داده پیدا نشد.

البته ممکن هم هست که کوئری بیشتر از یک نتیجه داشته باشد که در آن صورت هم کاربران موقع ورود به مشکل می‌خورند. شاید نتوانند وارد شوند و شاید هم به اکانت دیگری وارد شوند. یکی از دلایلی که اکثر سایت‌ها اجازه‌ی یکسان بودن یوزرنیم را نمی‌دهند هم همین است. چون یوزرنیم شما در دیتابیس‌ها به عنوان کلید و id شما عمل می‌کند. سایت‌هایی که به کاربران اجازه می‌دهند یوزرنیم یکسان داشته باشند احتمالا از یک عدد یا اطلاعات دیگری از کاربر که خاص باشد مثل ایمیل برای key یا id آن کاربر استفاده می‌کنند. البته که در وبسایت‌های مدرن خیلی کم پیش می‌آید یوزرنیم را به عنوان کلید اصلی انتخاب کنند چون در صورت داشتن قابلیت تغییر آن آپدیت کردن پایگاه داده سخت‌تر از موقعیتی خواهد بود که کلید اصلی یک id عددی باشد و یوزرنیم یک unique identifier که می‌تواند به عنوان alternate key عمل کند.

فرض کنید تصویر بالا قسمت لاگین سایت ما است که در بکندش کدی که نوشتیم هست. حالا بیاید فکر کنیم و ببینیم که چگونه می‌توانیم از همچین کد ناامنی سواستفاده کنیم! کد بالا رو وارد یک سیکوئل ادیتور می‌کنیم که راحت‌تر درک کنیم. شما هم می‌توانید هم زمان ما را در یک ادیتور همراهی کنید تا بهتر متوجه مطلب شوید. به رنگ‌ها دقت کنید!

فرض کنید کاربر در جایگاه ورودی username یک ' قرار دهد. در این صورت برای کوئری ما چه اتفاقی می‌افتد؟

همانطور که می‌بینید با قرار گرفتن ' در کوئری کوتیشن اول بسته می‌شود و تک کوتیشن دوم باز می‌ماند. چنین ورودی‌ای احتمالا به ما ارور می‌دهد. اگر با وارد کردن ' کاربر ارور بگیرد آن موقع می‌فهمد که سایت ما در مقابل سیکوئل اینجکشن محافظت نشده و می‌تواند از آن سواستفاده کند. حالا کوئری پایین را ببینید.

الان چه اتفاقی افتاد؟! این یکی از ساده‌ترین تریک‌های SQL Injection است. (که احتمالا به همین دلیل کمتر جایی پیدا می‌شود که هنوز در مقابل آن ایمن نباشد) اتکر با این روش تک کوتیشن کوئری خود سایت را می‌بندد و با OR به معنای «یا» یک شرط جدید به Query اضافه می‌کند. همه‌چیز را از یوزرز انتخاب کن که در آن یوزرنیم = خالی باشد یا یک مساوی یک! یک دومی فقط یک کوتیشن اولش دارد به این دلیل که می‌خواهیم کوتیشن باقی‌مانده خود کوئری را با آن ببندیم. احتمالا می‌توانید حدس بزنید که چنین کوئری‌ای تمام داده‌های یوزرز را برمی‌گرداند. البته اگر یادتان باشد بالاتر گفتیم که چند نتیجه از کوئری هنگام لاگین خیلی وقت‌ها به ارور منتهی می‌شود و اجازه‌ی ورود به ما نمی‌دهد. مثلا ممکن است برنامه‌نویس شرطی گذاشته باشد که در مواردی که تعداد نتیجه به جز ۰ و ۱ است (صفر برای اطلاعات ورودی غلط و ۱ برای ورودی درست) سایت ارور دهد. اگر چنین شرطی نباشد به احتمال زیاد ما وارد اولین اکانت ساخته شده می‌شویم که در بیشتر موارد یک اکانت ادمینی است. اگر شرط تنها ۰ و ۱ نتیجه وجود داشته باشد از روش زیر هم می‌توانیم استفاده کنیم:

لیمیت LIMIT یک دستور دیگر سیکوئل است که کارش محدود کردن تعداد نتیجه‌هاست LIMIT 1 یعنی فقط یک خط از جدول را به ما برگردان (خط اول) که با این کار می‌توانیم بعضی ارورها را دور بزنیم. اما نکته‌ی جالب‌تر در ورودی پسوورد بالا بعد از لیمیت است یعنی «--;». کارایی نقطه ویرگول یا سمی‌کالن(semicolon) و دو خط فاصله یا دش(dash) در اینجا چیست؟ اگر به قبل از لیمیت هم توجه کنید دیگر یک دوم فقط یک کوتیشن ندارد بلکه هر دو کوتیشن‌های اول و دومش را قرار دادیم. چرا؟ به شکلی که کوئری ما با این ورودی‌ها درآمده نگاه کنید. اگر به همان دستور قبلیمان در بالاتر فقط لیمیت اضافه می‌کردیم سیکوئل آن را داخل نقل قولمان یعنی تک کوتیشن‌ها به حساب می‌آورد پس یک تک کوتیشن بعد از ۱ اضافه می‌کنیم که آن را ببندیم. اما اینکار کافی نیست چون تک کوتیشن کوئری ثابت سایت باقی‌مانده است و اجرای این کوئری ارور می‌دهد. پس چطور از شر آن خلاص شویم؟ یک سمی‌کالن قرار می‌دهیم که کوئری را تمام کند و دو دش می‌گذاریم که بقیه‌ی دستوراتی که خود برنامه‌نویس نوشته را به کامنت تبدیل کند! (اگر به رنگ‌ها توجه کنید -- و بعد از آن به رنگ دیگری درآمده که نشان از کامنت بودن و اجرا نشدن آن است) به همین راحتی! البته همه‌ی RDBMSها علامت کامنتشان یکسان نیست ممکن است # یا چیز دیگری باشند پس SQL Injection به کمی آزمون و خطا و صبر نیاز دارد. مقدار کمی در اینجا و مقدار خیلی بیشتری در حمله‌های سخت‌تر و حرفه‌ای‌تر.

با یاد گرفتن این سینتکس‌های جدید احتمالا می‌توانید حدس بزنید که در بعضی موارد که دیگر سایت خیلی ناامن باشد (!) می‌توان حتی با فقط پر کردن قسمت یوزرنیم هم وارد یک سایت شد:

البته این روش در بیشتر مواقع به صورتی اجرا می‌شود که یوزرنیم را داریم و می‌خواهیم بدون رمز وارد شویم. مثلا می‌خواهیم وارد اکانت ادمین یا یوزری به اسم علی شویم:

آخرین مثال این قسمت یک کامیک طنز و برای نشان دادن این است که ایمن نبودن در برابر چنین حمله‌ای می‌تواند چقدر مخرب باشد: (DROP TABLE دستوری از سیکوئل است که کل یک جدول در پایگاه داده را پاک می‌کند)

Exploits of a Mom
Exploits of a Mom

قسمت جست‌وجو - search

فرض کنید که یک سایت فروش لوازم تحریر خیلی خیلی ساده (!) داریم و در قسمت جستجوی آن به دنبال خودکار می‌گردیم و نتیجه‌ی زیر به دست می‌آید. (احتمالا از ظاهر غیر حرفه‌ای همچین سایتی هم می‌توان تشخیص داد ناامن است!)

بیاید حدسی بزنیم که پشت این نتیجه چه کوئری‌ای نهفته است:

SELECT ? FROM ? WHERE ? LIKE 'Pen';

علامت سوال‌ها که معنایشان مشخص است؛ فقط آن‌ها را قرار داده‌ایم چون اسم‌های جدول و ستون‌هایمان را نمی‌دانیم. (در واقع در مثال‌های قبلی هم آن‌ها را به عنوان یک اتکر که کوئری پشت سایت را ندیده‌ است نمی‌دانیم و فقط برای درک بهتر اسم‌های ساده‌ای برای آن‌ها قرار دادیم.) اما LIKE چیست؟ لایک هم یک دستور سیکوئل است به این معنا که در پیدا کردن نتایج حروف کوچک و بزرگ را نادیده بگیر. (یعنی مثلا اگر کلمه ورودی کاربر pen بود و محصول Pen‌ آن را نمایش بده و هر حالت دیگری به جز این)

حالا بیاید فکر کنیم که چطور می‌توانیم از این کو‌ئری سواستفاده کنیم. اول می‌توانیم از همان روش‌های بالا برای تست کردن ایمنی سایت در مقابل SQL Injection استفاده کنیم. مثلا تک کوتیشن بگذاریم و ببینیم که ارور می‌گیریم یا نه و یا از یک شرط همیشه درست استفاده کنیم که ببینیم تمام محصولات را می‌بینیم یا نه. اما نکته‌ی جدیدی که در این قسمت یاد می‌گیریم روش استفاده از UNION است. UNION دستوری است که با آن می‌توان ردیف‌های جداول مختلف را با هم ترکیب کرد در صورتی که تعداد ستون‌هایشان یکی باشد. یعنی داده‌هایی از جدول دیگری به پایین جدول ما به صورت سطری اضافه می‌شوند. بذارید با مثال ببینیم البته هنوز از جدول دیگری استفاده نمی‌کنیم چون اسم جدولی را نمی‌دانیم:

SELECT ? FROM ? WHERE ? LIKE ' ' UNION SELECT 1, 2; -- ';

با این ورودی حالا ما همه‌ی محصولات را داریم به علاوه‌ی یک ردیف دیگر که در آن ۱ و ۲ وجود دارد. (سایتمان تازه افتتاح شده فقط ۴ محصول دارد!) شاید بگویید خب ۱ و ۲ به چه دردمان می‌خورد؟! حق با شماست به طور مستقیم به کارمان نمی‌آید اما یک کارایی که دارد این است که می‌فهمیم سرچ این سایت نسبت به سیکوئل اینجکشن ناامن است و می‌توانیم با UNION اطلاعات دیگری به دست آوریم فقط کافی است نام جدول‌های پایگاه داده‌ی سایت را بدانیم. خب اینجا سوالی که پیش می‌آید این است که از کجا؟ RDBMSها را یادتان هست؟ در بخش سیکوئل گفتیم این‌ها در بعضی از جزئیات فرق می‌کنند که می‌توان برای حمله‌ی دقیق‌تر از آن‌ها استفاده کرد. خب بالاخره به قسمتی که این جزئیات قابل استفاده‌اند رسیدیم. تمام ‌RDBMSها به طور دیفالت خودشان جداولی دارند که اطلاعاتی راجع به دیتابیس در آن‌ها ثبت شده است که در‍ این اطلاعات نام جدول‌ها و جزئیاتشان است! البته قبل از اینکه بتوانیم از این‌ها استفاده کنیم باید بفهمیم که اصلا سایت از چه RDBSMای استفاده می‌کند که پیدا کردن آن هم با استفاده از تفاوت‌های آن‌هاست. مثلا ارورهای مختلف (اگر ارورهای سایت بیش از اندازه به کاربر اطلاعات دهند) یا نتیجه‌ دادن سینتکس‌های مختلف چیزی مثل کامنت‌ها و یا امتحان کردن دستورهایی که فقط در سیستم خاص خود وجود دارند.

مثلا فرض کنید با کمک سرچ بار دستور زیر را وارد کوئری می‌کنیم:

SELECT ? FROM ? WHERE ? LIKE 'Pen' AND 0 = SLEEP(3); -- ';

اسلیپ دستوری در MySQL است که وقفه‌ی زمانی ایجاد می‌کند. در اینجا می‌گوییم خط‌هایی را برایم بیاور که در آن‌ها Pen باشد و اسلیپ مساوی صفر که صفر خروجی‌ای است که اسلیپ می‌دهد. یعنی به ازای هر سطری که در نتیجه باشد ۳ ثانیه مکث داریم که در اینجا جمعا ۶ ثانیه. یعنی اگر ۶ ثانیه طول بکشد که صفحه نتایج لود شود می‌فهمیم که سایت از سیستم MySQL استفاده می‌کند. همه‌ی RDBMSها دستوری مشابه این و یا دستورات دیگری دارند که با آن‌ها می‌توانیم بفهمیم دیتابیس روی کدام سیستم است. فرض کنید حالا این کارها را کردیم و با امتحان و خطا فهمیدیم پایگاه داده‌ی مد نظر ما MySQL است حالا چی؟ حالا می‌رویم سراغ آن جدولی که نام جدو‌ل‌های پایگاه در آن ثبت شده است. در مای‌اس‌کیوال این جدول را در information_schema.tables و به خصوص در ستون TABLE_NAME می‌توانیم پیدا کنیم.

SELECT ? FROM ? WHERE ? LIKE ' ' UNION (SELECT TABLE_NAME, 2 FROM information_schema.tables); -- ';

خب حالا اسم جدول‌هایمان را داریم. یک جدول دیگر در MySQL وجود دارد که در آن اسم ستون‌ها آمده و با استفاده از آن می‌توانیم ستون‌های جدول users را به طور زیر پیدا کنیم.

SELECT ? FROM ? WHERE ? LIKE ' ' UNION (SELECT COLUMN_NAME, 2 FROM information_schema.columns WHERE TABLE_NAME = 'users'); -- ';

این کوئری در نتیجه به ما ستون‌های جدول کاربران را در پایین محصولات می‌دهد که می‌تواند در آن‌ها نام کاربری، نوع کاربری، کد ملی، شماره موبایل، پسوورد hash‌ شده و خیلی چیزهای دیگر باشد که اتکر به راحتی می‌تواند آن‌ها را به دست آورد. البته اگر همچین وبسایت ضعیفی اصلا وجود داشته باشد شاید حتی رمز کاربران را هم هش نکرده باشد!

در واقعیت کمتر سایتی همچین شکلی دارد. سایت دیجی‌کالا را در نظر بگیرید:

البته سایت دیجی‌کالا قطعا در مقابل همچین حمله‌های ساده‌ای ایمن است و این صرفا مثالی است برای اینکه ببینید چنین حمله‌ای در واقعیت ممکن است چه شکلی داشته باشد وقتی سایتمان به این سادگی نیست. یک ویژگی خیلی مهم دستور UNION این است که تعداد ستون‌هایی کوئری که ما وارد می‌کنیم باید با ستون‌های کوئری خود سایت برابر باشد که پیدا کردن این تعداد در سایت‌های واقعی به راحتی سایت ساده مثال ما که با نگاه می‌فهمیدیم دو ستون دارد نیست. در چنین وقت‌هایی فقط با امتحان کردن و حدس زدن عدد‌های مختلف می‌توانیم تعداد آن را پیدا کنیم.

قسمت‌هایی که در عکس بالا علامت خوردند را ببینید. از این می‌فهمیم که کوئری حداقل ۶ ستون دارد. اما در سایت‌ها معمولا هنگام جستجوها علاوه بر اطلاعاتی که می‌بینیم ستون‌های دیگری هم از دیتابیس برگردانده می‌شود که همین باعث این است که به امتحان و خطا نیاز داشته باشیم. بعد از اینکه تعداد ستون‌ را با عدد گذاشتن پیدا کردیم باید ببینیم اطلاعاتی که نمایش داده می‌شوند در کدام ستون قرار دارند که از آن ستون‌ها از نمایش داده‌هایی که می‌خواهیم استفاده کنیم. مثلا اگر اسم محصول ستون بازگشتی ۴ است TABLE_NAME را در ستون ۴ قرار دهیم که بتوانیم ببینیم.

به جز ورود بی‌اجازه، دزدیدن اطلاعات و پاک کردن کامل دیتابیس، کارهای دیگری هم می‌توان با این حمله کرد. مثلا می‌توان از دستور INSERT INTO که برای وارد کردن داده به دیتابیس است، فردی خودش را به جایی که به آن تعلق ندارد اضافه کند مثلا از یک سرویس اشتراکی بدون پول اشتراک بگیرد. یا با دستور UPDATE داده‌های دیتابیس را تغییر دهد مثلا یک دانش‌آموز در سیستم مدرسه نمرات خودش را ۲۰ کند یا فرد دیگری با نفوذ به سیستم بانک به موجودی خود چند صفر اضافه کند! یا هرکار دیگری که با استفاده از دستورهای سیکوئل قابل اجرا باشد.

امیدوارم این مثال‌های ساده کمک کرده باشند که بهتر درک کنید SQL Injection چگونه عمل می‌کند هرچند که این مثال‌ها فقط حمله‌های خیلی ساده‌ای بودند که در واقعیت کمتر استفاده می‌شوند. همان طور که می‌بینید هرچه حمله پیچیده‌تر می‌شود به صبر و وقت بیشتری نیاز دارد البته ابزارهایی وجود دارند برای تست کردن امنیت سایت‌ها مثل sqlmap که این کارها را به صورت اتوماتیک در می‌آورند که سرعت کار را بالا می‌برد.

انواع SQLi

این حمله به سه دسته کلی In-band‌ و Inferential و Out of Band تقسیم می‌شود.

دسته‌ی In-band که به آن سیکوئل اینجکشن کلاسیک هم می‌گویند، شناخته‌شده‌ترین و راحت‌ترین نوع این حمله است. این نوع حمله وقتی است که اتکر نتیجه‌‌هایی که می‌خواهد را از همان کانال ارتباطی‌ای که دستورات سیکوئل را وارد می‌کند پس بگیرد و نتایج را به طور مستقیم ببیند. اکثر مثال‌هایی که در بالا زدیم در این دسته قرار می‌گیرند. این دسته خود نیز انواع مختلفی دارد که UNION Base‌d و Errors Based از معروف‌ترین آن‌هاست. Union Based نوعی از حمله است که از دستور UNION برای اضافه کردن اطلاعاتی که خواست خود برنامه‌نویس نبوده‌ است به داده‌های نمایشی نرم‌افزار استفاده می‌کند و همان حمله‌ای است که در قسمت جستجو از آن استفاده کردیم. در نوع Error Based اتکر سعی می‌کند با وارد کردن دستور‌های اشتباه انواع ارور‌ها را از سیستم بگیرد و از طریق آن راجع به پایگاه داده اطلاعات کسب کند.

دسته‌ی Inferential که به اسم Blind SQL Injection بیشتر شناخته می‌شود، حمله‌ای است که در آن بر خلاف حمله‌ی In band اتکر با دستوراتش نتیجه‌ای را مستقیما در برنامه مشاهده نمی‌کند. (که به همین دلیل به حمله‌ی blind به معنای نابینا معروف است) در این حمله اتکر به جای دیدن نتیجه‌ی مستقیم اطلاعاتی از دیتابیس را توسط پاسخ سرور و نرم‌افزار به دستوراتش به دست می‌آورد. به همین دلیل هم این دسته از دسته‌ی In-band زمان بیشتری می‌برد. از انواع این دسته حمله می‌توان به ‌Boolean based و Time based اشاره کرد. ‌بولین نوعی داده است که دو عضو درست و غلط یعنی True و False دارد. در این نوع اتکر با وارد کردن دستوراتی و پس گرفتن True یا False اطلاعات کسب می‌کند. Time based هم مشابه همین است که در آن اتکر با ترکیب کردن یک دستور وقفه با یک دستور درست و غلط مشابه قبلی با مشاهده‌ی وقفه نرم‌افزار یا عدم وقفه اطلاعاتش را به دست می‌آورد. اگر از مثال‌های بالا یادتان باشد در یکی از آن‌ها از دستور SLEEP استفاده کردیم که با استفاده از آن نوع RDBMS را فهمیدیم. آن مثال یک Blind سیکوئل اینجکشن Time-based بود.

دسته‌ی Out of Bound از دو دسته‌ی قبل خیلی کمیاب‌تر است. در این نوع حمله اتکر نتایج دستوراتش را در خود برنامه نمی‌گیرد و باید یک سرور دیگر خودش برای دریافت اطلاعات داشته باشد. (Listening Server) دلیل کمتر استفاده شدن حمله‌ی Out of Bound این است که لازم است در سروری که مورد حمله است تنظیماتی فعال باشد و همچنین اینکه از دو روش بالا سخت‌تر و زمان‌برتر است و به مهارب بیشتری نیاز دارد.

ممکن است جدا از چیزهایی که گفتیم؛ نام‌ها، دسته‌بندی‌ها و انواع دیگری هم از این حمله به گوشتان خورده باشد که آن‌ها در این سه دسته کلی یا ترکیبی از آن‌ها قرار می‌گیرند. مثلا Second Order SQL Injection حمله‌ای است که در آن اتکر چیزی را داخل دیتابیس اینجکت می‌کند که بعدا موقع انجام دادن عملیات کاربر دیگری در برنامه اجرا می‌شود.

کلام آخر

تقریبا از زمانی که SQL Injection در سال ۱۹۹۸ میلادی در مقاله‌ی جف فوریستال برای اولین بار ثبت شد بیشتر از ۲۰ سال می‌گذرد اما همچنان یکی از رایج‌ترین و خطرناک‌ترین حمله‌هاست و حتی در سال ۲۰۲۱ هم قربانیانی داشته است. انواع سایت‌ها و برنامه‌های بزرگ قربانی این حمله شده‌اند و این مقاله به دلیل این نوشته‌ شده است که راحتی و قابلیت فراوان این حمله را نشان دهد و برنامه‌نویسان را به خطرات ایمن نساختن برنامه خود به آن آگاه سازد. این مقاله تمرکزش بر جلوگیری نیست پس وارد روش‌های جلوگیری نمی‌شویم اما برای مطالعه بیشتر می‌توانید راجع به Parameterized statements و Input Validation و Escaping و Stored Procedures تحقیق کنید. البته همیشه بهتر است جدیدترین روش‌های جلوگیری را دنبال کنید و از مقالات قدیمی استفاده نکنید. مهم‌ترین نکته برای جلوگیری از سیکوئل اینجکشن این است: به ورودی‌های کاربر اعتماد نکنید!

منابع استفاده شده در این مقاله

منابع پیشنهادی برای مطالعه بیشتر


نویسنده: پرنیا اسحاقی | Parnia Eshaghi

دانشگاه آزاد اسلامی تهران مرکز
کلاس پایگاه داده

استاد: دکتر مریم حاجی اسمعیلی | دکترای علوم کامپیوتر از دانشگاه کینگستون لندن
Dr.Maryam Hajiesmaeili | PhD of computer science from Kingston university of London
در لینکدین ببینید.



sql injectionامنیت سایبریسیکوئل اینجکشناس‌کیوال اینجکشنsql injection attack
شاید از این پست‌ها خوشتان بیاید