SQL Injection یک نوع حمله سایبری است که به مهاجم این امکان را میدهد تا با وارد کردن دستورات SQL مخرب در فیلدهای ورودی یک برنامه، به پایگاه داده دسترسی پیدا کند. این روش به مهاجم اجازه میدهد تا دادههای حساس را بازیابی یا تغییر دهد، اطلاعات موجود را تخریب کند و رفتارهایی مانند دستکاری دادهها را انجام دهد. در واقع، مهاجم میتواند با استفاده از یک سری دستورات SQL خاص، به طور غیرمجاز وارد سیستم شود و به آن آسیب برساند. با استفاده از SQL Injection، یک مهاجم قادر است هویت کاربران دارای دسترسیهای بالا را جعل کرده و خود را به عنوان مدیر پایگاه داده معرفی کند. این حمله همچنین به مهاجم امکان میدهد تراکنشها و ماندههای حساب را تغییر دهد یا حتی کل پایگاه داده را بازیابی یا تخریب کند. در نتیجه، SQL Injection میتواند تهدیدی جدی برای امنیت دادهها و یکپارچگی سیستمهای اطلاعاتی باشد.
در دنیای فناوری اطلاعات امروز، SQL Injection معمولاً از طریق اینترنت و با ارسال دستورات SQL مخرب به یک API یا نقطه پایانی (endpoint) که توسط وبسایتها یا سرویسها ارائه میشود، صورت میگیرد. این حمله به مهاجم این امکان را میدهد که با سوءاستفاده از ضعف در اعتبارسنجی ورودیها در کوئریهای SQL، دادههای حساس یا اطلاعات پایگاه داده را به دست آورد. در شرایط بحرانیتر، حمله SQL Injection میتواند به مهاجم اجازه دهد تا به سطح دسترسی root دست پیدا کند و کنترل کامل سیستم را در اختیار گیرد. حمله SQL Injection به طور خاص از ضعفهایی که در اعتبارسنجی ورودیهای کاربر وجود دارد، استفاده میکند. زمانی که یک برنامه از ورودیهای غیرقابل اعتماد برای ساختن کوئریهای SQL به پایگاه داده استفاده کند، مهاجم میتواند این ورودیها را دستکاری کرده و ساختار کوئریها را تغییر دهد. این تغییرات میتوانند به مهاجم اجازه دهند تا به دادههای پایگاه داده دسترسی پیدا کرده، آنها را تغییر دهد یا حتی حذف کند. این نوع حمله، تهدیدی جدی برای امنیت اطلاعات و یکپارچگی سیستمهای دادهای است.
SQL Injection معمولاً به سه دسته تقسیم میشود:
In-band SQLi (Classic) ، Inferential SQLi (Blind) و Out-of-band SQLi.
در این روش، مهاجم از همان کانال ارتباطی برای انجام حملات و دریافت نتایج استفاده میکند. سادگی و کارایی in-band SQLi آن را به یکی از رایجترین انواع حملات SQLi تبدیل کرده است. این روش دو زیرشاخه دارد:
Error–based SQLi: در این روش، مهاجم اقداماتی انجام میدهد که باعث میشود پایگاه داده پیامهای خطا تولید کند. مهاجم میتواند از دادههایی که این پیامهای خطا فراهم میکنند برای جمعآوری اطلاعات در مورد ساختار پایگاه داده استفاده کند.
Union–based SQLi: این تکنیک از عملگر UNION SQL بهره میبرد که چندین عبارتSELECT تولید شده توسط پایگاه داده را به هم متصل میکند تا یک پاسخ HTTP واحد دریافت کند. این پاسخ ممکن است شامل دادههایی باشد که مهاجم میتواند از آنها استفاده کند.
در این روش، مهاجم دادههایی را به سرور ارسال میکند و پاسخ و رفتار سرور را مشاهده میکند تا بیشتر در مورد ساختار آن اطلاعات کسب کند. این روش به blind SQLi معروف است زیرا دادهها از پایگاه داده وبسایت به مهاجم منتقل نمیشود و بنابراین مهاجم نمیتواند اطلاعات مربوط به حمله را به صورت in-band مشاهده کند. حملات Blind SQLi به الگوهای پاسخدهی و رفتاری سرور وابسته هستند، بنابراین معمولاً زمان بیشتری برای اجرا نیاز دارند، اما ممکن است به همان اندازه مخرب باشند. این نوع SQLi میتواند به دستههای زیر تقسیم شود:
Boolean: مهاجم یک پرسوجوی SQL به پایگاه داده ارسال میکند که برنامه را مجبور به بازگشت نتیجه میکند. نتیجه بستگی به این دارد که پرسوجو درست باشد یا غلط. بر اساس نتیجه، اطلاعات موجود در پاسخ HTTP تغییر میکند یا بدون تغییر میماند. مهاجم میتواند براساس این تغییرات بفهمد که پرسوجو درست بوده یا غلط.
Time–based: مهاجم یک پرسوجوی SQL به پایگاه داده ارسال میکند که باعث میشود پایگاه داده قبل از واکنش منتظر بماند (برای مدتی در ثانیه). مهاجم میتواند از مدت زمانی که پایگاه داده برای پاسخدهی نیاز دارد، متوجه شود که پرسوجو درست بوده یا غلط. بر اساس نتیجه، پاسخ HTTP فوراً یا پس از مدت زمانی ایجاد میشود. مهاجم میتواند متوجه شود که پیام استفاده شده نتیجه درست یا غلط داشته است، بدون اینکه به دادههای پایگاه داده وابسته باشد.
مهاجم میتواند این نوع حمله را تنها زمانی انجام دهد که ویژگیهای خاصی در سرور پایگاه داده استفاده شده توسط برنامه وب فعال شده باشد. این حمله عمدتاً به عنوان جایگزینی برای تکنیکهایIn-band SQLi و Inferential SQLi به کار میرود. Out-of-band SQLiزمانی انجام میشود که مهاجم نتواند از همان کانال برای انجام حمله و جمعآوری اطلاعات استفاده کند، یا زمانی که سرور به اندازه کافی کند یا ناپایدار است که این اقدامات را انجام دهد. این تکنیکها به قابلیت سرور برای ایجاد درخواستهای DNS یا HTTP بستگی دارند که دادهها را به مهاجم منتقل میکنند.
برنامههایی که کوئریهای SQL را بر اساس ورودی کاربران اجرا میکنند، ممکن است در برابر حملات SQL Injection آسیبپذیر باشند. به عنوان مثال، یک برنامه وب میتواند از کوئریهای SQL برای اجرای فرآیند احراز هویت استفاده کند. در این فرآیند، کاربر نام کاربری خود را وارد میکند و برنامه از این ورودی برای جستجوی هش رمز عبور مرتبط با آن حساب کاربری در پایگاه داده استفاده میکند. اگر هش رمز عبور ارائه شده توسط کاربر با هش ذخیره شده در پایگاه داده مطابقت داشته باشد، کاربر احراز هویت شده و به حساب خود دسترسی پیدا میکند .اگر برنامه وب ورودی نام کاربری را به درستی اعتبارسنجی نکند، یک مهاجم میتواند ورودی دستکاری شدهای ارائه دهد که توسط برنامه به اشتباه تفسیر شود. برای مثال، کوئریهای SQL معمولاً از کاراکترهایی مانند تککوتیشن (”) یا دابلکوتیشن (“”) برای تعریف دادهها در دستورات خود استفاده میکنند. یک کوئری ساده برای جستجوی رکورد مشتری بر اساس نام کاربری ممکن است به این شکل باشد:
SELECT * FROM customers WHERE username="user"
یک مهاجم میتواند با وارد کردن یک ورودی خاص، ساختار کوئری را تغییر دهد تا از آن سوءاستفاده کند. بهعنوان نمونه، اگر مهاجم نام کاربری زیر را وارد کند:
user" OR "1"="1
کوئری SQL به این شکل تغییر میکند:
SELECT * FROM customers WHERE username="user" OR "1"="1"SELECT * FROM customers WHERE username="user" OR "1"="1"
این کوئری به جای جستجوی رکوردهایی که فقط با نام کاربری “user” مطابقت دارند، به صورت زیر عمل میکند:
این تغییر به مهاجم اجازه میدهد به اطلاعات حساس سایر کاربران دسترسی پیدا کند. همچنین، در برخی موارد، ممکن است مهاجم بتواند فرآیند احراز هویت را دور بزند و به عنوان کاربر دیگری وارد سیستم شود یا به دادههای بیشتری دسترسی پیدا کند. این نوع آسیبپذیری میتواند پیامدهای جدی امنیتی داشته باشد.
برای جلوگیری از حملات SQL Injection و مقابله با آنها در صورت وقوع، روشهای مؤثری وجود دارد که میتوان به کار برد.
اولین گام برای پیشگیری از حملات، اعتبارسنجی یا پاکسازی ورودیها است. این فرآیند شامل نوشتن کدی است که بتواند ورودیهای غیرمجاز کاربران را شناسایی کند. با وجود اینکه اعتبارسنجی ورودیها یکی از بهترین شیوههای امنیتی محسوب میشود، معمولاً به تنهایی کافی نیست. زیرا در بسیاری از موارد، امکان تعریف تمام ورودیهای مجاز و غیرمجاز به صورت جامع وجود ندارد و این کار ممکن است منجر به خطاهای اشتباه شود که تجربه کاربری و عملکرد برنامه را مختل میکند.
معمولاً از فایروال برنامه وب (WAF) برای فیلتر کردن حملات SQL Injection و سایر تهدیدات آنلاین استفاده میشود. فایروال برنامه وب با تکیه بر مجموعهای از امضاهای(Signatures) امنیتی که به صورت دقیق طراحی و مداوم به روزرسانی میشوند، توانایی شناسایی و مسدودسازی کوئریهای SQL مخرب را دارد. این امضاها برای شناسایی مسیرهای حمله خاص طراحی شدهاند و به طور منظم با قوانین جدید برای مسدودسازی آسیبپذیریهای تازه کشف شده به روزرسانی میشوند.
فایروالهای مدرن معمولاً با سایر سیستمهای امنیتی یکپارچه هستند و از این طریق اطلاعات بیشتری برای افزایش تواناییهای امنیتی خود دریافت میکنند.
به عنوان مثال، یک فایروال برنامه وب که با ورودی مشکوکی مواجه میشود، ممکن است قبل از مسدودسازی آن، دادههای IP مربوطه را بررسی کند.
هنگام توسعه وبسایت یا برنامه وب، میتوانید اقداماتی امنیتی را اعمال کنید که خطر حملات SQL Injection را به حداقل برساند. موارد زیر از مؤثرترین روشها برای پیشگیری از این حملات هستند:
همواره جدیدترین نرمافزارها و patchهای امنیتی ارائه شده توسط فروشندگان را نصب کنید.
حسابهای کاربری متصل به پایگاه داده را فقط با حداقل سطح دسترسی مورد نیاز پیکربندی کنید.
از اشتراکگذاری حسابهای پایگاه داده بین وبسایتها و برنامههای مختلف خودداری کنید.
برای تمامی انواع ورودیهای کاربر، از جمله فهرستهای کشویی (Drop-Down Menus)، اعتبارسنجی انجام دهید.
به جای ارسال پیامهای خطا به مرورگر کاربران، گزارشدهی خطا را به درستی پیکربندی کنید.
دستورات آماده (Prepared Statements) را همراه با کوئریهای پارامترسازی شده استفاده کنید تا تمامی کدهای SQL از قبل تعریف شوند و مقادیر پارامترها به صورت جداگانه ارسال شوند. این کار مانع از تغییر هدف کوئری توسط مهاجمان میشود.
رویههای ذخیره شده را برای ساخت کوئریهای SQL با پارامترهای تعریف شده در پایگاه داده به کار بگیرید. این رویهها از طریق برنامه اجرا میشوند.
از اعتبارسنجی allowlist برای جلوگیری از ورود دادههای غیرمعتبر به کوئریها استفاده کنید.
تمام ورودیهایی که از کاربر دریافت میشود را قبل از استفاده در یک پرسوجو به طور مناسب پردازش کنید تا از تداخل آنها با کد SQL جلوگیری شود. این کار مانع از اجرای دستورات غیرمجاز و حملات SQL Injection میشود.
توصیههای کلی:
حمله موفقیتآمیز SQL Injection میتواند عواقب جدی برای یک کسبوکار داشته باشد. این حمله میتواند به موارد زیر منجر شود:
مهاجمان میتوانند دادههایی را بازیابی کنند که احتمالاً دادههای حساس ذخیره شده روی سرور SQL را افشا میکند.
مهاجمان میتوانند اطلاعات موجود در سیستم شما را تغییر داده یا حذف کنند.
بسته به دادههای ذخیره شده روی سرور SQL، حمله میتواند اطلاعات حساس کاربران مانند آدرسها، شماره تلفنها و جزئیات کارتهای اعتباری را افشا کند.
اگر یک کاربر پایگاه داده دارای دسترسیهای مدیریتی باشد، مهاجم میتواند با استفاده از کد مخرب به سیستم دسترسی پیدا کند.
اگر از دستورات SQL ضعیف برای بررسی نام کاربری و رمز عبور استفاده کنید، مهاجم میتواند بدون دانستن اطلاعات کاربری وارد سیستم شما شود. از این مرحله به بعد، مهاجم میتواند با دسترسی و دستکاری اطلاعات حساس، آسیبهای بزرگی وارد کند.
هزینه حمله SQL Injection فقط مالی نیست و ممکن است شامل از دست دادن اعتماد مشتریان و آسیب به اعتبار شرکت نیز باشد. پس از شکسته شدن اعتماد مشتری، ترمیم آن بسیار دشوار خواهد بود.
این روش یکی از ابزارهای مؤثر برای کاهش حملات SQL Injection است. به جای نوشتن کوئریهای داینامیک که قادر به تمایز میان کد برنامه و دادهها نیستند، استفاده از دستورات آماده (Prepared Statements) باعث میشود تا توسعه دهندگان از کوئریهای ثابت SQL استفاده کنند و ورودیهای خارجی را به عنوان پارامتر به کوئری منتقل کنند. این رویکرد اطمینان میدهد که مفسر SQL همیشه قادر است کد برنامه را از دادهها جدا کند و مانع از اجرای دستورات مخرب شود. برای مثال، در اینجا روش authenticate()، پیادهسازی شده است:
در اینجا، صرفنظر از ورودی کاربر، متغیرهای زمان اجرا مانند نام کاربری و رمز عبور نمیتوانند بر رفتار کوئری تأثیر بگذارند. لازم به ذکر است که استفاده تنها از شیء PreparedStatement به تنهایی یک دفاع کافی نیست. برای جلوگیری از مشکلات امنیتی، باید این شیء به همراه ویژگی پارامترسازی (“?”) برای تمام مقادیر زمان اجرا استفاده شود. در غیر این صورت، استفاده از ترکیب رشتهها میتواند منجر به حمله SQL Injection شود، حتی اگر از شیء PreparedStatement نیز استفاده گردد.