آسیب پذیری تزریق SQL چیست؟ – راهنمای مقدماتی


آسیبپذیریهای تزریق کد بر اساس لیست 10 ریسک مهم امنیتی OWASP، به عنوان رایجترین آسیبپذیریها فهرستبندی شدهاند. آسیب پذیری تزریق SQL در اغلب موارد موجب مخاطراتی برای پایگاههای داده و اپلیکیشنها میشود که نتیجه آن نشت دادهها و دسترسیهای بدون مجوز است. درک این آسیبپذیریها برای همه افراد فعال در این حوزه حائز اهمیت است، چون باعث میشود که بتوانید به صورت فعالانهای از وقوع این موارد در اپلیکیشنها جلوگیری کنید.
- مقاله پیشنهادی: آموزش امنیت شبکه — راهنمای شروع و یادگیری
ایجاد پایگاه داده
ما در این مقاله برای درک بهتر آسیبپذیریها ابتدا یک پایگاه داده و اپلیکیشن نمونه میسازیم تا ببینیم SQL چگونه با یک اپلیکیشن معمولی تعامل پیدا میکند.
فرض کنید یک پایگاه داده ساده SQL دارید که شامل جدولی از کاربران به نام users به صورت زیر است:
در این جدول برخی کاربرهای نمونه را درج میکنیم تا دادههایی داشته باشیم که بتوانیم با آنها کار کنیم.
اینک یک پایگاه داده داریم که شبیه آن چیزی است که در اغلب اپلیکیشنها برای احراز هویت کاربران استفاده میشود. برای این که ببینیم چگونه میتوانیم با این پایگاه داده تعامل پیدا کنیم یک اپلیکیشن VB.net ابتدایی ساختهایم. در این اپلیکیشن یک فرم login ساده داریم:
کدهایی که فرم ورودی را دریافت کرده و نام کاربری و رمز عبور وارد شده را با مقادیر موجود در پایگاه داده مطابقت میدهند به صورت زیر هستند:
تست اپلیکیشن
اینک میتوانیم اپلیکیشن خود را تست کنیم تا ببینیم کوئری های SQL چگونه ساخته میشوند و به چه روشی روی پایگاه داده اجرا میشوند. اگر یک «نقطه توقف» (breakpoint) اضافه کنیم، میتوانیم اپلیکیشن را به صورت مرحله به مرحله اجرا کنیم تا ببینیم که مقادیر هر متغیر در هر لحظه چه قدر است و به این ترتیب درک بهتری از آن چه رخ میدهد خواهیم داشت. در آغاز کاربر اطلاعات ورود خود را وارد میکند و روی دکمه «Login» کلیک میکند.
زمانی که این کار صورت گرفت، کوئری SQL به بررسی آن چه کاربر ساخته میپردازد و ورودیهای نام کاربر و رمز عبور را در یک کوئری الحاق کرده و آن را روی پایگاه داده اجرا میکند. کوئری SQL چیزی مانند زیر است:
نکته مهم که باید توجه داشت این است که این کوئری چگونه ساخته میشود. ورودی کاربر به صورت مستقیم وارد کوئری میشود و سپس کوئری روی پایگاه داده اجرا میشود. در کوئری فعلی، نتیجه اجرا در صورت یافتن مورد مطابقت نام کاربری و رمز عبور روی پایگاه داده، مقدار 1 را بازگشت میدهد و این رفتار مورد انتظار و درستی است. اما اگر کاربر یک کاراکتر ‘ در کوئری خود وارد کرده باشد چطور؟
اینک کوئری به صورت زیر ساخته میشود:
اگر اجازه بدهیم این کوئری روی پایگاه داده اجرا شود، نتیجه زیر به دست میآید:
مخاطرات پایگاه داده
همان طور که میبینید که یک استثنای SQL دریافت شده که میگوید ساختار SQL نادرست است. در واقع زمانی که کاربر کاراکتر ‘ را در فیلد مربوطه وارد میکند، این کاراکتر به کوئری وارد میشود و کوئری نیز روی پایگاه داده اجرا میشود. SQL کاراکتر ‘ را به عنوان یک پایان نقل قول برای رشته نام کاربری تفسیر میکند و یک مورد عدم مطابقت گیومه رخ میدهد که موجب بروز خطای نحوی در کوئری میشود.
این وضعیت مناسبی نیست زیرا کاربر میتواند با وارد کردن یک کاراکتر منفرد موجب از کار افتادن برنامه ما شود. اما این وضعیت زمانی بدتر میشود که کاربر بتواند آسیب بسیار بیشتری را از طریق دستکاری کامل در کوئری وارد سازد. ورودی زیر را تصور کنید:
اگر مهاجم بخواهد این مقادیر را وارد کند، کوئری حاصل به صورت زیر خواهد بود:
این کوئری را تجزیه میکنیم تا آن را بهتر درک کنیم. با استفاده از این فیلتر مهاجم میخواهد همه مدخلهایی را که ‘’ = Username و 1 =1 باشد دریافت کند، از آنجا که 1 همواره برابر با 1 است، این کوئری همه رکوردهای موجود را بازگشت میدهد. قطعه آخر ورودی یعنی دو خط تیره در واقع یک کامنت در SQL است. هر چیزی پس از این دو کاراکتر نادیده گرفته میشود.
نتیجه اجرای این کوئری بازگشت دادن تعداد همه چیز در پایگاه داده Users است. از آنجا که این موارد بیشتر از 1 خواهند بود، کاربر مجوز دسترسی به اپلیکیشن را خواهد یافت؛ هر چند که اطلاعات ورود معتبر را وارد نکرده است!
راهکار چیست؟
این وضعیت مسلماً وضعیت بدی است چون ما هرگز نمیخواهیم که کاربری بتواند بدون اطلاعات درست به یک اپلیکیشن دسترسی پیدا کند. بنابراین چگونه میتوان از بروز این مشکل اجتناب کرد؟
برخی افراد ممکن است پیشنهاد دهند که همه کاراکترهای ‘ را حذف کنیم. اما تصور کنید که ممکن است ما یک کلمه معتبر مانند O’Reily را در ورودی خود داشته باشیم. بنابراین باید به دنبال راهحل بهتری باشیم.
بهترین پاسخ به این مسئله «کوئریهای پارامتری شده» (parameterized queries) است. کوئریهای پارامتری شده، طرح اجرایی SQL را پیش از افزودن ورودی ایجاد میکنند. یعنی از اجرای کد وارد شده از سوی کاربر جلوگیری میکنند. اگر بخواهیم کد اولیه خود را بر اساس کوئریهای پارامتری شده بازنویسی کنیم، چیزی مانند زیر به دست میآید:
انجام این کار موجب حل مشکل ما خواهد شد:
نسخه پارامتری شده از کوئری به طرز چشمگیری امنتر است و به امن ماندن اپلیکیشن در برابر حملههای تزریق SQL کمک زیادی میکند. استفاده از این روش هنگام دسترسی به پایگاه داده SQL بسیار حائز اهمیت است چون در غیر این صورت دادههای شما از سوی مهاجمان تخریب شده یا مورد دسترسی غیرمجاز قرار میگیرند.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای دروس مهندسی کامپیوتر
- آموزش امنیت وردپرس (WordPress Security)
- مجموعه آموزشهای ابزارها و راهکارهای مدیریت وبسایت ها
- آموزش امنیت شبکه — راهنمای شروع و یادگیری
- آموزش امنیت در شبکه های کامپیوتری و اینترنت
- آشنایی با ۷ پروتکل امنیت ایمیل — به زبان ساده
- امنیت در سیستم عامل — راهنمای جامع
- آموزش SQL Server Management Studio | کامل، رایگان و گام به گام
==