در این مقاله توضیح خواهیم داد که SQL Injection چیست، چند نمونه متداول را شرح می دهیم، چگونگی یافتن و بهره برداری از انواع مختلف آسیب پذیری SQL Injection را توضیح می دهیم و چگونگی جلوگیری از SQL Injection را به طور خلاصه بیان خواهیم کرد.
تزریق SQL چیست ؟
حمله تزریق SQL، آسیب پذیری امنیتی وب است که به یک هکر اجازه می دهد تا با سؤالاتی که یک برنامه در دیتابیس خود ایجاد می کند مداخله کند.
به طور کلی به یک مهاجم اجازه می دهد تا داده هایی را که معمولاً قادر به بازیابی نیستند مشاهده کند. این موضوع ممکن است شامل داده های کاربران یا هر داده دیگری باشد که برنامه به آن دسترسی دارد.
در بسیاری موارد، یک مهاجم می تواند این داده ها را تغییر داده یا حذف کند و باعث ایجاد تغییرات مداوم در محتوا یا رفتار برنامه شود.
در برخی شرایط، یک مهاجم می تواند با حمله تزریق SQL، سرور اصلی یا سایر زیرساخت های back-end را به خطر بیاندازد یا یک حمله denial-of-service را انجام دهد.
تأثیر حمله تزریق کد SQL چیست؟
حمله موفقیت آمیز SQL Injection می تواند منجر به دسترسی غیر مجاز به داده های حساس مانند گذرواژه ها، اطلاعات کارت اعتباری یا اطلاعات شخصی کاربر شود.
بسیاری از موارد نقض داده های مشهور در سال های اخیر نتیجه حملات SQL Injection بوده و منجر به صدمه به اعتبار و جریمه های نظارتی شده است.
در بعضی موارد، یک مهاجم می تواند یک پشتیبان مداوم را در سیستم های سازمان بدست آورد و منجر به سازش طولانی مدت شود که می تواند برای مدت طولانی بدون اینکه شناسایی شود کار خود را ادامه دهد.
انواع تزریق SQL
طیف گسترده ای از آسیب پذیری ها، حملات و تکنیک های SQL Injection وجود دارد که در شرایط مختلف ایجاد می شوند. برخی از نمونه های معمول تزریق SQL عبارتند از:
- بازیابی داده های پنهان، جایی که می توانید یک درخواست SQL را برای بازگشت نتایج اضافی اصلاح کنید.
- برهم زدن منطق برنامه، جایی که می توانید یک سوال را برای تغییر در منطق برنامه تغییر دهید.
- حمله به UNION، که در آن می توانید داده ها را از جداول پایگاه داده های مختلف بازیابی کنید.
- بررسی بانک اطلاعاتی، جایی که می توانید اطلاعات مربوط به نسخه و ساختار بانک اطلاعات را استخراج کنید.
- تزریق کور SQL، که در آن نتایج جستجوی شما کنترل شده در پاسخ برنامه نیست.
1. بازیابی داده های پنهان
یک برنامه خرید را در نظر بگیرید که محصولات را در دسته های مختلف نمایش می دهد. وقتی کاربر بر روی دسته هدایا کلیک کند، مرورگر، URL را درخواست می کند:
“https://insecure-website.com/products?category=Gifts”
این امر باعث می شود تا یک نرم افزار SQL برای بازگرداندن جزئیات مربوط به محصولات از پایگاه داده، از یک SQL Query استفاده کند:
SELECT * FROM products WHERE category = 'Gifts' AND released = 1
این پرس و جو (SQL query) از database اطلاعات زیر را درخواست می کند:
- all details (*)
- from the products table
- where the category is Gifts
- and released is 1.
“released = 1” برای مخفی کردن محصولاتی که عرضه نمی شوند، استفاده می شود. برای محصولات منتشر نشده “released = 0” استفاده می شود.
این برنامه هیچگونه دفاعی را در برابر حملات تزریق SQL پیاده سازی نمی کند، بنابراین یک مهاجم می تواند حمله ای مانند:
“–‘https://insecure-website.com/products?category=Gifts”
نتیجه جستجوی SQL به صورت زیر می باشد:
SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1
نکته اصلی در اینجا این است که توالی دو خط “–” یک شاخص در SQL است و به این معنی است که بقیه پرس و جو به عنوان یک تفسیر تعبیر می شود.
این موضوع به طور تاثیر گذاری باقی مانده پرس و جو را از بین می برد، بنابراین دیگر “1=AND released” منتشر نمی شود. این بدان معنی است که همه محصولات از جمله محصولات غیرمجاز نمایش داده می شوند.
با پیشروی بیشتر، یک مهاجم می تواند باعث شود، برنامه تمام محصولات را در هر گروه از جمله دسته هایی که از آن ها هیچکس خبر ندارد نمایش دهد:
” –https://insecure-website.com/products?category=Gifts’+OR+1=1 “
نتیجه در جستجوی SQL به صورت زیر می باشد:
SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1
پرس و جوی اصلاح شده، تمام مواردی را که در آن دسته از هدایا 1 برابر با 1 است را نشان می دهد، از آنجا که 1 = 1 همیشه درست است، پرس و جو تمام موارد را برمی گرداند.
2.برهم زدن منطق برنامه
برنامه ای را در نظر بگیرید که به کاربران اجازه می دهد با یک نام کاربری و رمز عبور وارد شوند. اگر کاربر نام کاربری و رمز عبور را ارسال کند، برنامه با انجام SQL زیر، اعتبار نامه را بررسی می کند:
'SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese
اگر پرس و جو، جزئیات یک کاربر را بازگرداند، ورود به سیستم موفقیت آمیز خواهد بود. در غیر این صورت درخواست پذیرفته نمی شود.
در این بخش، یک مهاجم می تواند مانند هر کاربر و بدون رمز ورود به سادگی با استفاده از”SQL comment--
” وارد سیستم شود.
بخش چک کردن رمز عبور را از قسمت “WHERE” انجام میدهد و آن را حذف می کند. به عنوان مثال، ارسال نام کاربری ” –‘administrator “و یک رمز عبور خالی به صورت خط زیر:
''=SELECT * FROM users WHERE username = 'administrator'--' AND password
می تواند کاربر را که نام کاربری آن administrator است از دیتابیس دریافت کند و هکر خود را به جای کاربر ثبت کند.
3.حمله به UNION
در مواردی که نتایج یک پرس و جو SQL در پاسخ برنامه ها برگردانده شود، مهاجم می تواند از آسیب پذیری SQL Injection برای بازیابی داده ها از جداول دیگر در پایگاه داده استفاده کند.
این کار با استفاده از کلمه کلیدی UNION انجام می شود و به شما امکان می دهد “Select query” اضافی را نیز انجام دهید و نتایج را به پرس و جو اصلی اضافه کنید.
به عنوان مثال، اگر برنامه ای درخواست زیر را که حاوی ورودی کاربر “gifts” است، اجرا کند:
'SELECT name, description FROM products WHERE category = 'Gifts
سپس هکر می تواند ورودی زیر را ارسال کند:
--UNION SELECT username, password FROM users
این امر باعث می شود برنامه تمام نام های کاربری و کلمات عبور را به همراه نام و توضیحات محصولات بازگرداند.
4.بررسی بانک اطلاعاتی
پس از شناسایی اولیه آسیب پذیری SQL Injection، به طور کلی دستیابی به برخی اطلاعات در مورد خود پایگاه داده مفید است. این اطلاعات اغلب می تواند راه را برای بهره برداری بیشتر هموار کند.
می توانید جزئیات نسخه مربوط به پایگاه داده را پرس و جو کنید. نحوه انجام این کار بستگی به نوع بانک اطلاعاتی دارد، بنابراین می توانید نوع پایگاه داده را از هر تکنیک دیگری بدست آورید. به عنوان مثال، در Oracle می توانید این کار را انجام دهید:
SELECT * FROM v$version
همچنین می توانید تعیین کنید که جداول بانک اطلاعاتی وجود دارد و کدام ستون ها را شامل می شود. به عنوان مثال، در اکثر بانک های اطلاعاتی می توانید عبارت زیر را برای لیست کردن جدول ها اجرا کنید:
SELECT * FROM information_schema.tables
5.تزریق کور SQL
بسیاری از موارد تزریق SQL آسیب پذیری کور است. این بدان معناست که برنامه نتایج جستجوی SQL یا جزئیات هرگونه خطای پایگاه داده را در پاسخ های خود باز نمی گرداند.
از آسیب پذیری های کور هنوز هم می توان برای دسترسی به داده های غیر مجاز استفاده کرد، اما تکنیک های موجود عموماً پیچیده تر و دشوار هستند.
بسته به ماهیت آسیب پذیری و پایگاه داده، از تکنیک های زیر می توان برای سوءاستفاده از آسیب پذیری های تزریق کور SQL استفاده کرد:
- شما می توانید منطق پرس و جو را تغییر دهید تا بسته به حقیقت یک شرط واحد، اختلاف قابل تشخیص در پاسخ برنامه ایجاد شود. این ممکن است شامل تزریق یک شرایط جدید به برخی از منطق بولی و یا ایجاد مشروط مانند خطای تقسیم بر صفر باشد.
- شما می توانید به طور مشروط یک تأخیر زمانی در پردازش پرس و جو ایجاد کنید که به شما این امکان را می دهد تا واقعیت شرط را بر اساس زمانی که برنامه پاسخ می دهد استنباط کنید.
- با استفاده از تکنیک های OAST می توانید تعامل خارج از باند شبکه را آغاز کنید. این روش بسیار قدرتمند است و در شرایطی کار می کند که تکنیک های دیگر این کار را انجام ندهند. شما می توانید مستقیماً داده ها را از طریق کانال خارج از باند، مجزا کنید، به عنوان مثال با قرار دادن داده ها در جستجوی DNS برای دامنه ای که شما کنترل می کنید.
نحوه تشخیص آسیب پذیری های تزریق SQL
اکثر آسیب پذیری های تزریق SQL را می توان به سرعت و با اطمینان با استفاده از اسکنر آسیب پذیری وب “Burp Suite” یافت.
SQL Injection می تواند به صورت دستی و با استفاده از یک مجموعه سیستماتیک از تست در برابر هر نقطه ورود به برنامه تشخیص داده شود. به طور معمول شامل موارد زیر است:
- ارسال شخصیت نقل قول واحد و به دنبال خطا یا ناهنجاری های دیگر.
- ارسال برخی از نحوه های خاص SQL که به مقدار پایه (اصلی) از نقطه ورود و به یک مقدار دیگر ارزشیابی می کنند و به دنبال تفاوت های سیستماتیک در پاسخ های برنامه کاربردی هستند.
- ارسال شرایط بولی مانند 1 = 1 و 1 = 2 و جستجوی تفاوت در پاسخ برنامه.
- ارسال بار های با هدف ایجاد تأخیر در هنگام اجرای درخواست در SQL و به دنبال تفاوت در زمان لازم برای پاسخگویی هستید.
- ارسال بار های OAST با هدف ایجاد تعامل شبکه خارج از باند هنگام اجرای یک پرس و جو SQL و نظارت بر هرگونه تعامل حاصل از آن، طراحی شده است.
تزریق SQL در قسمت های مختلف پرس و جو
بیشتر آسیب پذیری های تزریق SQL در بند “WHERE” از “SELECT Query” بوجود می آیند. این نوع تزریق SQL معمولاً توسط آزمایش کنندگان باتجربه قابل درک است.
اما آسیب پذیری های تزریق SQL در اصل می توانند در هر مکانی از پرس و جو و در انواع مختلف نمایش داده شود. رایج ترین مکان ها که در آن تزریق SQL بوجود می آید یه شرح زیر می باشد:
- در بیانیه های UPDATE، در مقادیر به روز شده یا بند WHERE.
- در عبارت INSERT، درون مقادیر درج شده.
- در عبارت SELECT، در جدول یا نام ستون آمده است.
- در بیانیه های SELEC، در بند ORDER BY.
تزریق مرتبه دوم SQL
تزریق مرتبه اول SQL در جایی بوجود می آید که برنامه از کاربر درخواست HTTP دریافت کرده و در طی پردازش آن، ورودی را در یک پرس و جو SQL به روشی ناامن وارد می کند.
در تزریق SQL مرتبه دوم (که به عنوان تزریق SQL نیز شناخته می شود)، برنامه از درخواست HTTP ورودی کاربر را می گیرد و آن را برای استفاده بعدی ذخیره می کند.
این کار معمولاً با قرار دادن ورودی در یک پایگاه داده انجام می شود، اما در نقطه ای که داده ها ذخیره می شوند، آسیب پذیری ایجاد نمی شود.
بعداً هنگام رسیدگی به درخواست HTTP، برنامه داده های ذخیره شده را بازیابی می کند و آن را به روش نا امن در یک پرس و جو SQL می گنجاند.
تزریق مرتبه دوم SQL اغلب در شرایطی بوجود می آید که توسعه دهندگان از آسیب پذیری های تزریق SQL آگاه هستند و بنابراین با اطمینان می توانید محل اولیه ورود به پایگاه داده را کنترل کنید.
وقتی داده ها بعدا پردازش می شوند، بی خطر تلقی می شوند، زیرا در گذشته با خیال راحت در پایگاه داده قرار گرفته اند. در این مرحله، داده ها به شیوه ای نا امن اداره می شوند، زیرا توسعه دهنده فکر می کند که این موضوع قابل اعتماد است.
عوامل خاص در پایگاه داده
برخی از ویژگی های اصلی زبان SQL به همان روش در سراسر سیستم عامل های پایگاه داده محبوب اجرا می شود، بنابراین بسیاری از روش های شناسایی و بهره برداری از آسیب پذیری های تزریق SQL به طور یکسان در انواع مختلف بانک اطلاعاتی کار می کنند.
با این وجود تفاوت های زیادی بین بانک های اطلاعاتی مشترک نیز وجود دارد. این بدان معنی است که برخی از تکنیک های تشخیص و بهره برداری از تزریق SQL بر روی سیستم عامل های مختلف کار می کنند. مثلا:
- Syntax for string concatenation.
- Comments.
- Batched (or stacked) queries.
- Platform-specific APIs.
- Error messages.
نحوه جلوگیری از تزریق SQL
بیشتر موارد تزریق SQL با استفاده از پرس و جو های پارامتری (همچنین به عنوان عبارت های آماده شناخته شده) به جای جمع کردن رشته در پرس و جو قابل پیشگیری هستند.
کد زیر در برابر تزریق SQL آسیب پذیر است زیرا ورودی کاربر مستقیماً در پرس و جو محاسبه می شود:
String query="SELECT * FROM products WHERE category="'"+input+"'"
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);
این کد به راحتی می تواند به شکلی نوشته شود که از دخالت ورودی کاربر در ساختار پرس و جو جلوگیری کند:
PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?");
statement.setString(1, input);
ResultSet resultSet = statement.executeQuery();
نمایش داده های پارامتری برای هر شرایطی که ورودی غیرقابل اعتماد به عنوان داده در پرس و جو ظاهر می شود، از جمله بند WHERE و مقادیر در عبارت INSERT یا UPDATE استفاده می شود.
از آن ها نمی توان برای کنترل ورودی غیرقابل اعتماد در سایر قسمت های پرس و جو، مانند نام جدول یا ستون یا بند ORDER BY استفاده کرد.
عملکرد برنامه های کاربردی که داده های غیرقابل اعتماد را در آن بخش از پرس و جو قرار می دهد، نیاز به رویکرد متفاوتی دارد، مانند لیست ورودی مقادیر مجاز یا استفاده از منطق مختلف برای ارائه رفتار مورد نیاز.
برای اینکه یک پرس و جو پارامتری در جلوگیری از تزریق SQL موثر باشد، رشته ای که در پرس و جو استفاده می شود باید همیشه ثابت دارای کدگذاری سخت باشد و هرگز نباید حاوی داده های متغیر از هر مبدأ باشد.
وسوسه نشوید که در مورد اینکه آیا به یک مورد داده اعتماد دارید تصمیم بگیرید و همچنان برای مواردی که از نظر امنیت در نظر گرفته شده است، استفاده از اتصال رشته را در پرس و جو ادامه دهید.
اشتباه کردن در مورد منشأ احتمالی داده ها یا تغییر در کد دیگر برای پیش فرض درباره داده هایی که رنگ می شوند، بسیار ساده است.
بیشتر بخوانید