پرش به محتوا

تزریق اس‌کیوال

از ویکی‌پدیا، دانشنامهٔ آزاد

تزریق به پایگاه داده (به انگلیسی: SQL injection)، نوعی فنّ تزریق کد است که نقص امنیتی نرم‌افزار وب‌سایت را اکسپلویت می‌کند. به‌این صورت که نفوذگر با یک سری دستورهای اس‌کیوال، عملیاتی را (متفاوت با عملیات عادی موردنظر طرّاح وبسایت) در پایگاه داده وب‌سایت آسیب‌پذیر انجام می‌دهد.

این آسیب‌پذیری جزء ده آسیب‌پذیری رایج نرم‌افزارهای وب در سال ۲۰۰۷ و ۲۰۱۰ برشمرده شده‌است.[۱]

تزریق SQL یک روش حمله است که هدف آن داده‌های ساکن در پایگاه داده‌ای است که از طریق Firewall محافظت می‌شود. حمله معمولاً به علت مدیریت ضعیف در اعتبارسنجی کدها یا ورودی‌های برنامه (وب‌سایت) اتفاق می‌‌افتد. حملهٔ تزریق SQL زمانی اتفاق می‌افتد که یک مهاجم، قادر به قرار دادن یک سری از عبارت‌های SQL در یک Query (پرس‌وجو) با دستکاری داده‌های ورودی کاربر در یک برنامهٔ مبتنی بر وب می‌باشد. البته این مسئله نیز مستقیماً با نحوهٔ مدیریت کدها و ورودی‌های وب‌سایت رابطهٔ مستقیم دارد. یک حمله‌کننده می‌تواند از نقص‌های برنامه‌نویسی یا حفره‌های امنیتی وب‌سایت یا نرم‌افزار به‌راحتی برای دستیابی به اطّلاعات یک پایگاه داده استفاده نماید.

پرس‌وجوی معمول دارای چند بخش مختلف به شرح ذیل می‌باشد:

  1. دستور Select: با استفاده از این دستور ستون‌هایی که مورد نظرمان است را انتخاب می‌نمائیم.
  2. From: که مشخص می‌نماید که ستون‌های مورد نظر ما از کدام جدول انتخاب شوند.
  3. Where: که در آن شروطی را مشخص می‌کنیم.
  4. و یک سری دستورات، عبارات، و... دیگر.

حملات تزریق از طریق SQL فقط در بخش شرطی Where اتفاق می‌افتند. در ادامه توضیح خواهیم داد که این مسئله چگونه رخ می‌دهد.

پیاده‌سازی فنی

[ویرایش]

فیلتر اشتباه کاراکترهای "" یا

[ویرایش]

این آسیب‌پذیری از راه‌های گوناگونی پدید می‌آید. یک طریق فیلتر نشدن کراکترهای (" و ') است. برای مثال:

statement = "SELECT * FROM users WHERE name = '" + userName + "';"

کار این کد استخراج اطلاعات یک نام کاربری (که به متغیر داده می‌شود) از جدول users است. اما نفوذگر می‌تواند با دادن مقدارهایی هوشمندانه به متغیر userName، سبب اجرای دستورهایی متفاوت از آنچه موردنظر کدنویس بوده‌است بشود. برای مثال با وارد کردن این کد به عنوان ورودی:

' OR 'a'='a

کد نهایی اینچنین رندر می‌شود:

SELECT * FROM users WHERE name = '' OR 'a'='a';

همچنین می‌توان با یکی از این سه روش، ادامهٔ کد را کامنت گرفت:[۲]

' OR 'a'='a' -- '
' OR 'a'='a' ({ '
' OR 'a'='a' /* '

که نتیجه چنین است:

SELECT * FROM users WHERE name = '' OR 'a'='a' -- ';

مثلاً ممکن است در کدی، ادامهٔ کد، مربوط به بررسی گذرواژه باشد. در آن حالت با این کار آن بخش از کد، کامنت گرفته می‌شود و پردازش نمی‌شود. به این ترتیب نفوذگر بدون واردکردن گذرواژه از مانع می‌گذرد.

یا مثلاً واردشدن چنین عبارتی:

a'; DROP TABLE users; SELECT * FROM userinfo WHERE 't' = 't

سبب حذف جدول users و نیز استخراج تمام اطلاعات جدول userinfo می‌شود.

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

SELECT * FROM users WHERE name = 'a';DROP TABLE users; SELECT * FROM userinfo WHERE 't' = 't';

در حالی که بسیاری از پیاده‌سازی‌های SQL Server امکان اجرای چندین دستور را در یک فراخوان، مانند این مثال، فراهم می-کنند، برخی از رابط‌های برنامه کاربردی SQL مثل تابع؛ ()mysql_query در زبان PHP به دلایل امنیتی اجازه این عملیات را نمی‌دهند. این محدودیت باعث جلوگیری از تزریق Queryهای کاملاً مجزا از هم توسط مهاجمان می‌شود، اما نمی‌تواند مانع تغییر Queryها شود.

مدیریت نادرست نوع ورودی

[ویرایش]

این شکل از تزریق زمانی اتفاق می‌افتد که یک فیلد کاربر از نظر محدودیت‌های نوع ورودی بررسی نشده باشد. این اتفاق زمانی می‌تواند رخ دهد که یک فیلد عددی در یک دستور SQL استفاده شده باشد، اما برنامه‌نویس هیچ‌گونه بررسی برای تعیین نوع ورودی کاربر و تأیید ورودی عددی، فراهم نساخته باشد. برای مثال:

statement := "<syntaxhighlight lang="sql" inline>SELECT * FROM userinfo WHERE id = </syntaxhighlight>" + a_variable + ";"

با توجه به این دستور واضح است که برنامه‌نویس a-variable را برای تعیین عدد مرتبط با فیلد id در نظر گرفته‌است. با این حال، اگر ورودی از نوع رشته تعیین شده باشد، کاربر نهایی می‌تواند دستور را به صورت دلخواه دستکاری کرده و به این وسیله نیاز به ورود کراکترهای Escape شده را دور بزند. برای مثال مقداردهی a-variable به صورت زیر جدول "users" را از پایگاه داده حذف خواهد کرد:

1;DROP TABLE users

چرا که دستور SQL معادل آن به صورت زیر خواهد شد:

SELECT * FROM userinfo WHERE id=1;DROP TABLE users;

تزریق SQL کور

[ویرایش]

این اصطلاح زمانی استفاده می‌شود که یک برنامه تحت وب در برابر تزریق SQL آسیب‌پذیر است، اما نتایج تزریق برای مهاجمان قابل رؤیت نیست. صفحه دارای آسیب‌پذیری ممکن است آن صفحه‌ای نباشد که داده‌ها را نمایش می‌دهد، اما تفاوت‌های حاصل از نتایج یک دستور تزریق منطقی به درون یک دستور SQL مشروع را، که برای صفحه مورد نظر فراخوانی شده‌است، نمایش خواهد داد. این نوع حمله با افزایش زمان، ممکن است شدیدتر شود، زیرا برای هر بیت بازیابی شده، ساخت یک دستور نیاز است. ابزارهایی وجود دارد که پس از به‌دست آوردن اطلاعات مربوط به هدف و مکان آسیب‌پذیری، امکان خودکار کردن این حمله را فراهم می‌کنند.[۳]

پاسخ‌های شرطی

[ویرایش]

نوعی از تزریق SQL کور است که پایگاه داده را مجبور به ارزیابی یک دستور منطقی بر روی صفحه یک برنامه معمولی می‌کند. به عنوان مثال یک وب‌سایت مرور کتاب از یک رشته Query برای مشخص کردن اینکه مرور کدام کتاب نمایش داده شود، استفاده می‌کند؛ بنابراین آدرس http://books.example.com/showReview.php?ID=5 باعث خواهد شد سرور Query زیر را اجرا کند:

SELECT * FROM bookreviews WHERE ID = 'Value(ID)';

که منجر به نمایش خلاصه مربوط به کتابی که با ID5 در جدول bookreview ذخیره شده‌است، خواهد شد. Query به‌طور کامل در سرور اتفاق می‌افتد؛ کاربر نام‌های مربوط به پایگاه داده، جدول یا فیلدها را نمی‌داند و از رشته Query نیز اطلاع ندارد. کاربر فقط می‌بیند که آدرس بالا خلاصه یک کتاب را برمی‌گرداند. یک هکر می‌تواند آدرس‌های http://books.example.com/showReview.php?ID=5 AND 1=1 و http://books.example.com/showReview.php?ID=5 AND 1=2 را بارگذاری کند که به ترتیب به صورت دستورها SQL زیر تبدیل می‌شوند:

SELECT * FROM bookreviews WHERE ID = '5' AND '1'='1';
SELECT * FROM bookreviews WHERE ID = '5' AND '1'='2';

اگر با آدرس "۱=۱" خلاصه اصلی بارگذاری شود و با اجرای آدرس "۲=۱" صفحه خطا یا خالی برگردانده شود، سایت احتمالاً در مقابل حمله تزریق SQL آسیب‌پذیر است.

هکر می‌تواند با وارد کردن رشته Query زیر موفق به کشف شماره نسخه MySQL در حال اجرا بر روی سرور شود: http://books.example.com/showReview.php?ID=5 AND substring(@@version,1,1)=4، که خلاصه کتاب را در صورتی که سرور بر روی MySQL 4 در حال اجرا باشد، نمایش خواهد داد و در غیر این صورت یک صفحه خطا یا خالی را نشان خواهد داد. هکر با استفاده از کد درون رشته‌های Query می‌تواند به اطلاعات بیشتری از سرور دست یابد تا مسیر اصلی حمله را کشف کرده و به اهداف خود دست یابد.[۴][۵]

تزریق SQL سطح دوم

[ویرایش]

این تزریق زمانی اتفاق می‌افتد که مقادیر ارائه شده شامل حملات تزریق SQL باشد که به جای برخی دستورها اجرایی ذخیره شده‌اند. برنامه کاربردی ممکن است یک دستور SQL را به درستی رمزنگاری کرده و آن را به صورت یک دستور SQL معتبر ذخیره کند. سپس بخش دیگری از برنامه که بدون هیچ‌گونه کنترلی برای محافظت در برابر تزریق SQL طراحی شده‌است، ممکن است دستور SQL ذخیره شده را اجرا کند. این حمله نیازمند آگاهی بیشتر در مورد این است که مقادیر ارائه شده، بعداً چگونه استفاده خواهند شد. اسکن کننده‌های امنیت برنامه‌های کاربردی تحت‌وب خودکار به آسانی نمی‌توانند این گونه حمله را تشخیص دهند و ممکن است نیاز باشد که به صورت دستی، برای بررسی علائم این حمله، دستورنویسی شود.

کاهش خطر

[ویرایش]

دستورها پارامتریک

[ویرایش]

با توسعه بیشتر platformها، دستورها پارامتریک که با پارامترها کار می‌کنند می‌توانند به جای تعبیه ورودی کاربر در دستورها استفاده شوند (گاهی متغیر یا متغیرهای bind نامیده می‌شوند). یک متغیر تنها می‌تواند مقدار یک نوع داده و نه یک قطعه SQL دلخواه را ذخیره کند. از این رو تزریق SQL به راحتی به صورت یک مقدار پارامتری ناآشنا (و احتمالاً نامعتبر) عمل می-کند. در بسیاری از موارد، دستور SQL ثابت است و هر پارامتر یک اسکالر است و نه یک جدول. سپس ورودی کاربر به یک پارامتر اختصاص داده می‌شود (bound می‌شود).[۶]

اجرا در سطح برنامه‌نویسی

[ویرایش]

استفاده از کتابخانه‌های نگاشت مبتنی بر ارتباط اشیاء، نیاز به نوشتن کدهای SQL را برطرف می‌کند. کتابخانه ORM تحت تأثیر کدهای شیء گرا، دستورها SQL پارامتریک را تولید می‌کند.

Escaping

[ویرایش]

یک راه ساده اما مستعد خطا برای جلوگیری از تزریق، Escape کردن کاراکترهایی است که در SQL معنای خاصی دارند. راهنمای پایگاه داده SQL توضیح می‌دهد که کدام کراکترها معنی خاص دارند، بنابراین این امکان را فراهم می‌کند که یک فهرست سیاه جامع از کاراکترهایی که نیاز به ترجمه دارند تهیه شود. برای مثال، هر رخداد از نقل قول تکی (') در یک پارامتر، باید توسط دو نقل قول ('') جایگزین شود تا به شکل یک رشته SQL معتبر تبدیل شود. برای مثال، در PHP معمولاً پارامترها قبل از ارسال Query، به کمک تابع mysql_real_escape_string(); اسکیپ می‌شوند:

$mysqli = new mySqli('hostname', 'db_username', 'db_password', 'db_name');
$query = sprintf("SELECT * FROM `Users` WHERE UserName='%s' AND Password='%s'",
                  $mysqli->real_escape_string($Username),
                  $mysqli->real_escape_string($Password));
$mysqi->query($query);

نکته: در حال حاضر از عملکرد mysql نارضایتی وجود دارد، بنابراین از استفاده از آن اجتناب شده و به جای آن از 'mysqli' استفاده می‌شود.[۷]

این تابع، مثلاً ()mysql_real_escape_string، تابع mysql_real_escape_string را از کتابخانه MySQL فراخوانی می‌کند، که به کاراکترهایی که بعد از backslashها می‌آیند توجه می‌کند:\x00, \n, \r, \, ', " و \x1a. این تابع باید همیشه (به جز چند استثنا) پیش از ارسال Query به MySQL برای ساخت داده امن استفاده شود.[۸]
توابع دیگری برای انواع پایگاه داده در PHP وجود دارد مانند ()pg_escape_string برای PostgreSQL. با این حال یک تابع وجود دارد که برای Escape کردن کراکترها کار می‌کند و به‌طور خاص برای گرفتن Query از پایگاه‌های داده‌ای که توابعی برای Escaping در PHP ندارند، استفاده می‌شود. این تابع (addslashes(string $str است. یک رشته برمی‌گرداند که شامل backslashهایی است که پیش از کراکترهای مورد نیاز در گزارش‌گیری از پایگاه داده، قرار می‌دهد. این کراکترها نقل قول تکی (')، نقل قول (")، backslash (\) و کراکتر پوچ (NULL) هستند.[۹]
به‌طور معمول عبور رشته‌های Escape شده به SQL مستعد خطا است زیرا امکان فراموش کردن Escape کردن رشته داده وجود دارد. ساخت یک لایه شفاف برای امن کردن ورودی می‌تواند این استعداد خطا را کاهش دهد، هر چند که به‌طور کامل آن را از بین نمی‌برد.[۱۰]

بررسی الگو

[ویرایش]

پارامترهای بولی، شناور یا صحیح می‌توانند از نظر نوع بررسی شوند که مقادیر مطابق با نوع آن‌ها وارد شده باشد. رشته‌هایی که باید برخی الگوها را رعایت کنند (تاریخ، UUID، … و غیره) می‌توانند بررسی شوند که با این الگوها مطابقت داشته باشند.

مجوزهای پایگاه داده

[ویرایش]

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

deny select on sys.sysobjects to webdatabaselogon;
deny select on sys.objects to webdatabaselogon;
deny select on sys.tables to webdatabaselogon;
deny select on sys.views to webdatabaselogon;
deny select on sys.packages to webdatabaselogon;

در ژوئیهٔ ۲۰۱۲ گروهی تحت عنوان D33D با نفوذ به زیر دامنه‌ای از یاهو، Yahoo Voices، به همین شیوه، گواهی‌نامه‌های لاگین بیش از ۴۵۰۰۰۰ کاربر این وبگاه را ربودند.[۱۱]

منابع

[ویرایش]
  1. «Category:OWASP Top Ten Project - OWASP». بایگانی‌شده از اصلی در ۱ دسامبر ۲۰۱۹. دریافت‌شده در ۲۵ ژانویه ۲۰۱۲.
  2. IBM Informix Guide to SQL: Syntax. Overview of SQL Syntax > How to Enter SQL Comments, IBM[پیوند مرده]
  3. "Using SQLBrute to brute force data from a blind SQL injection point". Justin Clarke. Archived from the original on 14 June 2008. Retrieved October 18, 2008.
  4. macd3v. "Blind SQL Injection tutorial". Archived from the original on 14 December 2012. Retrieved 6 December 2012.
  5. Andrey Rassokhin. "TDSS botnet: full disclosure". Archived from the original on 9 December 2012. Retrieved 6 December 2012. {{cite web}}: Unknown parameter |coauthors= ignored (|author= suggested) (help)
  6. "SQL Injection Prevention Cheat Sheet". Open Web Application Security Project. Archived from the original on 16 November 2015. Retrieved 3 March 2012.
  7. "mysql Introduction - PHP Manual". PHP.net.
  8. "mysqli->real_escape_string - PHP Manual". PHP.net.
  9. "Addslashes - PHP Manual". PHP.net. Archived from the original on 5 September 2011. Retrieved 20 November 2013.
  10. "Transparent query layer for MySQL". Robert Eisele. November 8, 2010.
  11. Chenda Ngak. "Yahoo reportedly hacked: Is your account safe?", CBS News. July 12, 2012. Retrieved July 16, 2012.

پیوند به بیرون

[ویرایش]