اگر اهل مباحث امنیت وب یا برنامه نویسی تحت وب باشید، حتما با نامهای SQL و SQL Injection آشنا هستید. در این پست خواهید دانست که اس کیو ال اینجکشن چیست و چگونه عمل میکند.
[highlight]این پست تنها با هدف افزایش اطلاعات منتشر شده است. هر گونه سوء استفاده از گفته های این پست بر عهده کاربر است.[/highlight]
تزریق به دیتابیس (SQL Injection) چیست؟
تزریق به پایگاه داده یا دیتابیس (SQL Injection) نوعی از حملات وب است که در آن فرد حمله کننده یا هکر میتواند اقدام به اجرا کردن دستورات دلخواه و مخرب خود بر روی پایگاه داده وب سایت مورد هدف کند. در این حمله، حمله کننده با استفاده از دانش خود (یا تنها با استفاده از یک برنامه ساده!) میتواند از نقضهای امنیتی موجود در کدهای نوشته شده توسط برنامه نویس سایت استفاده کرده و به اصطلاح آنها را اکسپلویت کند. چون در این حمله هکر درواقع به کد اسکیوال، کد دلخواه خود را اضافه میکند، تزریق SQL نام گرفته است.
یک حمله موفق اس کیو ال اینجکشن میتواند به راحتی سبب افشای دادههای مهم در دیتابیس (ازجمله رمزهای عبور، اطلاعات فردی کاربران و …)، اضافه کردن دادههای دلخواه حمله کننده به دیتابیس یا حذف کردن دادههای خاص از دیتابیس گردد.
چگونه از باگ SQL Injection جلوگیری کنیم؟
نحوه جلوگیری از باگ SQL Injection نیاز به آگاهی برنامه نویس تحت وب از نحوه عملکرد این باگ دارد و جلوگیری از آن بسیار ساده تر از چیزی است که معمولاً تصور میشود. به همین دلیل یک پست جداگانه با عنوان نحوه جلوگیری از باگ تزریق به دیتابیس یا SQL Injection منتشر کرده ایم و در آن نحوه جلوگیری از این باگ را بررسی کرده ایم. برای جلوگیری از باگ، به پست زیر مراجعه کنید:
اصلاح و جلوگیری از باگ SQL Injection
حمله SQL Injection چگونه کار میکند؟
فرض کنید شما یک برنامه نویس سمت وب هستید و قصد دارید با دیتابیس از طریق دستورات SQL ارتباط برقرار کنید. چون همانطور که میدانید استفاده از زبان SQL برای برقراری ارتباط با دیتابیس ضروری است. کد زیر را فرض کنید که در زبان PHP نوشته شده است:
$sql_statement = “SELECT * FROM users WHERE name = ‘” . $_GET[“name”] . “‘”;
دستور بالا مقدار فیلد یا همان پارامتر username که توسط متد GET، متدی که پارامترها در مسیر URL مشخص میشوند، از طرف کاربر به سرور ارسال شده را در بین دو علامت ‘ قرار میدهد (تا توسط سرور SQL به عنوان رشته حروفی شناخته شود) و پس از آن فرض کنید که مقدار موجود در متغیر $sql_statement قرار است اجرا شود.
فرض کنید که کاربر فیلد name را به صورت عادی مثل مقدار زیر پر کند. مسیر از طریق متد GET به این شکل خواهد شد:
http://example.com/vul.php?name=Amirreza
در این صورت Query موجود در متغیر sql_statement به این صورت خواهد بود:
$sql_statement = “SELECT * FROM users WHERE name = ‘Amirreza‘”;
و کوئری (حرف همزه به دلیل فونت سایت مانند ن نشان داده میشود) بدون مشکل اجرا خواهد شد. در دیتابیس فیلد name با رشته Amirreza مقایسه خواهد شد و در جایی که نتیجه یافت شد، همه فیلدها (*) برای بقیه کدها در دسترس خواهد بود.
حال فرض کنید که کاربر (در اینجا، حمله کننده) فیلد name را به صورت زیر پر کند:
http://example.com/vul.php?name=’ UNION UPDATE users SET email = ‘[email protected]’ WHERE name = ‘admin’
به یک نام کاربری شبیه نیست، درست است؟ خب حال این مقدار را جایگزین پارامتر username متد POST میکنیم. متغیر کوئری ما به این شکل خواهد بود:
$sql_statement = “SELECT * FROM users WHERE name = ‘‘ UNION UPDATE users SET email = ‘[email protected]’ WHERE name = ‘admin‘”;
خب کوئری بالا هم اجرا خواهد شد ولی با این تفاوت که در واقع هکر کوئری دلخواه خود را اجرا کرده است! در دیتابیس فیلد name با رشته خالی جستجو خواهد شد ولی چیزی پیدا نخواهد شد، تا اینجا برای هکر مهم نیست. اما هکر با استفاده از دستور UNION، کوئری دوم خود را نیز اجرا میکند و در کوئری دوم، ایمیل کاربر admin (که به احتمال زیاد تمامی دسترسیهای موجود را دارد) را به ایمیل دلخواه تغییر (UPDATE) میدهد.
یک مثال دیگر:
فرض کنید در یک صفحه Login (ورود)، کاربر یوزرنیم و پسورد را به وبسایت ارسال میکند. در سمت سرور، یک کوئری با شرط وجود و برابری یوزرنیم و پسورد در دیتابیس اجرا میشود. اگر کوئری خروجی داشت، یک نشست (Session) ایجاد شده و به کاربر دسترسی ورود میدهد اما اگر هیچ خروجی ای نبود، یعنی یوزر پیدا نشده یا رمز برابر نبوده، در این صورت از ورود کاربر جلوگیری میشود. فرض کنیم کد کوئری ما به این صورت باشد:
$query = “SELECT name, phone FROM users WHERE username='” . $_POST[“username”] . “‘ AND passwd = ‘” . $_POST[“password”] . ‘”;
فرض کنید کاربر به صورت عادی یوزرنیم و پسورد خود را وارد میکند. در نتیجه پارامترهای زیر با متد POST (چون از فرم استفاده شده) ارسال میشوند:
username = administrator
password = MyP@$SW0Rd
کوئری به صورت زیر خواهد بود:
$query = “SELECT name, phone FROM users WHERE username=’administrator‘ AND passwd = ‘MyP@$SW0Rd‘”;
چون یک رکورد با شرط برابر بودن فیلدهای username و passwd با مقادیر دریافت شده وجود دارد، کاربر به داخل پنل هدایت خواهد شد.
حال فرض کنید یک هکر یا حمله کننده مقادیر پارامترها را به صورت زیر ارسال کند:
username = ‘ OR ‘1’ = ‘1
password = ‘ OR ‘1’ = ‘1
کوئری به صورت زیر خواهد بود:
$query = “SELECT name, phone FROM users WHERE username=’‘ OR ‘1’ = ‘1‘ AND passwd = ‘‘ OR ‘1’ = ‘1‘”;
عملگر OR یک کار بسیار مهم انجام خواهد داد. در کوئری بالا برنامه به این صورت عمل میکند:
فیلدهای name و phone را از تیبل users بگیر به شرط این که در یکی از رکوردها، مقدار username برابر {خالی} باشد یا اگر ۱ برابر ۱ باشد و شرط دوم هم این که مقدار passwd برابر {خالی} باشد یا اگر ۱ برابر ۱ باشد.
خب میدانیم که همیشه مقدار ۱ برابر ۱ است پس هر دو شرط همیشه درست خواهند بود و در خروجی این کوئری، همه رکوردهای موجود بیرون داده خواهد شد. و چون رکوردی با شرط کوئری (درواقع شرط تقلبی ما) پیدا شد، حمله کننده به پنل منتقل خواهد شد!
سلام. ممنون از اطلاعات خوبتون.
مطالب خیلی ساده و گویا ارائه شده بود.
خواهش میکنم 🙂 زنده باشید.
بسیار ممنون…بسیار جالب بووود و کاربردی بووود ….خیلی سپاسگزارم از سایت خوبتووون
زنده باشید دوست عزیز 🙂
با سلام امیررضا جان
اگر برنامه نویس از دستور try catch استفاده کند دیگر حطا مشاهده نمی شود پس باید چکار کرد؟
سلام. اگه گزینه نشون دادن خطا بسته باشه و از ترای کچ به صورت صحیح استفاده کنه دیگه اروری نمیبینه کاربر. با این حال ممکنه هنوز دیتابیسش به Blind SQL Injection آسیب پذیر باشه.
سلام من علاقه ی زیادی به برنامه نویسی و هک دارم اگر شما میتونید بهم یاد بدهید تو تلگرام بهم پیام بدین آیدی من تو تلگرام:
@mohsen_0512
حداقل به سوالام جواب بدین منم مثل شما اهل آذربایجان شرقی هستم به هم استانی تون کمک کنید
درضمن سایت خوبی دارید
باتشکر
سلام. خیلی خوشحالم که هم استانی هستیم ولی امکان آموزش چنین مباحثی وجود نداره.