نکته امنیتی شماره سوم Øملات موسوم به
SQL Injection
پیش از هر چیز سعی Ù…ÛŒ*کنم تعریÙÛŒ از SQL Injection بياورم اين خيلي مهمه كه بدونيم معني اين كلمه چيست اين واژه به معناي تزريق SQL هست Ùˆ خوب Ùکر Ù…ÛŒ کنم دیگه Øالا بشه Øدس زد Ú©Ù‡ این یعنی Ú†ÛŒ. یعنی اینکه یک کسی یک طوری یک چیزی رو به یک پایگاه داده SQL تزريق مي كنه تزريق هميشه يادآور اينه كه ماده اي خارجي كه از جنس مقصد نيست به اون وارد مي شه Ùˆ اين واقعا همون چيزيه كه اتÙاق ميÙته Øالا با بیانی ساده آغاز Ù…ÛŒ*کنیم Ùˆ به سراغ این Ù…ÛŒ*رویم Ú©Ù‡ اگر برنامه*های ما در مقابل این نوع Øملات ضع٠داشته باشند چگونه Ù…ÛŒ*توانند مورد Øمله واقع شوند.
در واقع سه نوع Øمله از اين دست وجود دارند كه دوتا از اونها مد نظر ما هستند
1- Øملاتي كه ناشي از اشتباه در Ùيلترينگ گريزكاركترها(escape characters)هستند
2- Øملاتی Ú©Ù‡ ناشی از اشتباه در نوع داده هستند
3- Øملاتی Ú©Ù‡ به ØÙره های ذاتی پایگاه های داده مربوط Ù…ÛŒ*شوند
پر ÙˆØ§Ø¶Ø Ø§Ø³Øª Ú©Ù‡ دو دسته اول مدنظر ماست Ú©Ù‡ ادامه به بررسی اونها خواهیم پرداخت.
خوب اجازه بدهید در مورد اولی مثالی ببینیم
همونطوری Ú©Ù‡ مشاهده Ù…ÛŒ کنیم مانند همیشه خیلی عادی دارید نام کاربری Ú©Ù‡ کاربر براتون با متد GET پست كرده رو جستجو مي كنيد كه اگر ياÙت كرديد به اون كاربر اجازه ورود بديد هدÙمون اصلا اين نيست كه اين كد رو پيچيده كنيم مثلا شما با خودتون بگين كه اگر من باشم Øتما با POST Ù…ÛŒ Ùرستم Ùˆ Øتما پسورد را هم Ú†Ú© Ù…ÛŒ کنم Ùˆ Øتما پسورد را دوبار md5 مي كنم زيرا كه اصلا ØÙره در اينجا نيست تصور كنيد كه يك Ù†Ùوذگر(نه هکر) چنين چيزي را ارسال كند:
' OR '1'='1
و نتیجه نهایی در پرس و جوی SQL چنين مي شود
mysql_query('SELECT * FROM user WHERE username = "' . ' OR '1'='1 . '");
خوب Øالا نظرتون چیه!
Ù…ÛŒ دونین مشکل اینجاست Ú©Ù‡ قضیه به این سادگی ها هم ختم نمی شه Ùˆ Ù…ÛŒ شه یک Ù†Ùوذگر ماهر ده ها مورد دیگر رو هم مورد استÙاده قرار بده بطور مثال:
a';DROP TABLE users; SELECT * FROM data WHERE name LIKE '%
که نتیجه تعص٠برانگیز
را به همراه خواهد داشت موارد دیگر مانند بوجود آوردن خطاها Ùˆ گرÙتن اطلاعات بدست آوردن نسخه پایگاه داده اجرا کردن کدها Ùˆ مباØØ« پیشرÙته SQL Injection رو نام برد كه در هر مورد سخنان زيادي مي شه Ú¯Ùت Øالا اجازه دهيد كه به سراغ ØÙره دوم برويم :
ÙˆØ§Ø¶Ø Ø§Ø³Øª Ú©Ù‡ برنامه نویس در اینجا انتظار دارد Ú©Ù‡ متغیری عددی در جای variable وارد گردد Øال اگر بدون كنترل كردن نوع داده اين كد را در اختيار كاربران بگذارد به چنين چيزي روبرو مي شود
1;DROP TABLE users
Ùˆ اØتمالا دیگر نیازی نیست Ú©Ù‡ بگویم بعدا Ú†Ù‡ اتÙاقی خواهد اÙتاد خوب Øالا Ú†Ù‡ باید کرد؟
Øقیقت این است Ú©Ù‡ اگر ØÙره های امنیتی عموما کابوسی ÙˆØشت ناک بشمار Ù…ÛŒ آیند اما پیش گیری از آنها بسیار ساده است دو کد برای شما ذکر Ù…ÛŒ کنم Ú©Ù‡ منبع اون ها یکی از سایتهایی بود Ú©Ù‡ چند وقت پیش در این زمینه مطالعه Ù…ÛŒ کردم Ùˆ الان آدرس اونها در ذهنم نیست
در مورد ØÙره اول تابعی را Ù…ÛŒ نویسیم Ú©Ù‡ بسیار ساده Ùˆ در عین Øال Ù…ØÚ©Ù… Ùˆ قابل اعتماد است
Ùˆ Ù†Øوه استÙاده از اون هم بسیار ساده است
در مورد نکته دوم هم Ú©Ù‡ کلاس امیرمØمد عزیز رو مورد استÙاده قرار دادم Ú©Ù‡ یکی از مجموعه های بدرد بخور PEAR هست Ùˆ به آدرس http://pear.php.net/package/Validate Ù…ÛŒ تونین اون رو دریاÙت کنین Ùˆ آدرسی Ú©Ù‡ در کد هست رو به مسیر دلخواهی Ú©Ù‡ این Ùایل درون قرار داره تغییر بدین
خوب Øالا چند مورد اضاÙÛŒ هم باید ذکر کنم در مورد کد اول چند تابع Ù…ÛŒ بینید Ú©Ù‡ برای پاسخ به Øس کنجکاوی شما توضیØÛŒ براشون نمیارم ولی در پایگاه های داده گوناگون توابع در نظر گرÙته شده تقریبا به همین Ø´Ú©Ù„ هستند
* MySQL: mysql_real_escape_string()
* PostgreSQL: pg_escape_string()
* SQLite: sqlite_escape_string()
راه ØÙ„ خوب دیگری Ú©Ù‡ Øتما باید ذکر گردد استÙاده از PDO است كه در اينجا مجالي براي Ø´Ø±Ø Ø¢Ù† نیست Ùˆ توضیØاتی در این زمینه را Ù…ÛŒ تونین در
http://ir2.php.net/pdo
Ùˆ
http://www.devshed.com/c/a/PHP/Using...ects-in-PHP-5/
مشاهده کنید مورد سوم Ú©Ù‡ شخصا شدیدا اون رو توصیه Ú©Ù‡ نه دستور Ù…ÛŒ دهم استÙاده از DAL هاست كه شخصا پيشنهادم PEAR::MDB2 هست اما هر سه گزينه زير قابل تامل Ùˆ بدرد بخور هستند
AdoDB: http://adodb.sourceforge.net/
PEAR::MDB2: http://pear.php.net/package/MDB2
Zend_Db: http://framework.zend.com/manual/en/zend.db.html
SQL Injection
پیش از هر چیز سعی Ù…ÛŒ*کنم تعریÙÛŒ از SQL Injection بياورم اين خيلي مهمه كه بدونيم معني اين كلمه چيست اين واژه به معناي تزريق SQL هست Ùˆ خوب Ùکر Ù…ÛŒ کنم دیگه Øالا بشه Øدس زد Ú©Ù‡ این یعنی Ú†ÛŒ. یعنی اینکه یک کسی یک طوری یک چیزی رو به یک پایگاه داده SQL تزريق مي كنه تزريق هميشه يادآور اينه كه ماده اي خارجي كه از جنس مقصد نيست به اون وارد مي شه Ùˆ اين واقعا همون چيزيه كه اتÙاق ميÙته Øالا با بیانی ساده آغاز Ù…ÛŒ*کنیم Ùˆ به سراغ این Ù…ÛŒ*رویم Ú©Ù‡ اگر برنامه*های ما در مقابل این نوع Øملات ضع٠داشته باشند چگونه Ù…ÛŒ*توانند مورد Øمله واقع شوند.
در واقع سه نوع Øمله از اين دست وجود دارند كه دوتا از اونها مد نظر ما هستند
1- Øملاتي كه ناشي از اشتباه در Ùيلترينگ گريزكاركترها(escape characters)هستند
2- Øملاتی Ú©Ù‡ ناشی از اشتباه در نوع داده هستند
3- Øملاتی Ú©Ù‡ به ØÙره های ذاتی پایگاه های داده مربوط Ù…ÛŒ*شوند
پر ÙˆØ§Ø¶Ø Ø§Ø³Øª Ú©Ù‡ دو دسته اول مدنظر ماست Ú©Ù‡ ادامه به بررسی اونها خواهیم پرداخت.
خوب اجازه بدهید در مورد اولی مثالی ببینیم
کد:
mysql_query('SELECT * FROM user WHERE username = "' . $_GET['username'] . '");
' OR '1'='1
و نتیجه نهایی در پرس و جوی SQL چنين مي شود
mysql_query('SELECT * FROM user WHERE username = "' . ' OR '1'='1 . '");
خوب Øالا نظرتون چیه!
Ù…ÛŒ دونین مشکل اینجاست Ú©Ù‡ قضیه به این سادگی ها هم ختم نمی شه Ùˆ Ù…ÛŒ شه یک Ù†Ùوذگر ماهر ده ها مورد دیگر رو هم مورد استÙاده قرار بده بطور مثال:
a';DROP TABLE users; SELECT * FROM data WHERE name LIKE '%
که نتیجه تعص٠برانگیز
کد PHP:
mysql_query('SELECT * FROM user WHERE username = "' . a';DROP TABLE users; SELECT * FROM data WHERE name LIKE '%
. '");
را به همراه خواهد داشت موارد دیگر مانند بوجود آوردن خطاها Ùˆ گرÙتن اطلاعات بدست آوردن نسخه پایگاه داده اجرا کردن کدها Ùˆ مباØØ« پیشرÙته SQL Injection رو نام برد كه در هر مورد سخنان زيادي مي شه Ú¯Ùت Øالا اجازه دهيد كه به سراغ ØÙره دوم برويم :
کد PHP:
mysql_query("SELECT * FROM user WHERE id = " + variable + ";");
1;DROP TABLE users
Ùˆ اØتمالا دیگر نیازی نیست Ú©Ù‡ بگویم بعدا Ú†Ù‡ اتÙاقی خواهد اÙتاد خوب Øالا Ú†Ù‡ باید کرد؟
Øقیقت این است Ú©Ù‡ اگر ØÙره های امنیتی عموما کابوسی ÙˆØشت ناک بشمار Ù…ÛŒ آیند اما پیش گیری از آنها بسیار ساده است دو کد برای شما ذکر Ù…ÛŒ کنم Ú©Ù‡ منبع اون ها یکی از سایتهایی بود Ú©Ù‡ چند وقت پیش در این زمینه مطالعه Ù…ÛŒ کردم Ùˆ الان آدرس اونها در ذهنم نیست
در مورد ØÙره اول تابعی را Ù…ÛŒ نویسیم Ú©Ù‡ بسیار ساده Ùˆ در عین Øال Ù…ØÚ©Ù… Ùˆ قابل اعتماد است
کد PHP:
function sql_quote( $value )
{
if( get_magic_quotes_gpc() )
{
$value = stripslashes( $value );
}
//check if this function exists
if( function_exists( "mysql_real_escape_string" ) )
{
$value = mysql_real_escape_string( $value );
}
//for PHP version < 4.3.0 use addslashes
else
{
$value = addslashes( $value );
}
return $value;
}
کد PHP:
$username = $_POST['username'];
query = "SELECT * FROM users WHERE username='" . sql_quote($username) . "'";
کد PHP:
//init validate object
include_once('your_path_to_pear_directory/Validate.php');
$validate = &new Validate();
//get POST variables
$username = $_POST['username'];
$email = $_POST['email'];
$age = $_POST['age'];
//validate username, only alphanumeric and space characters are allowed
//VALIDATE_ALPHA, VALIDATE_NUM, VALIDATE_SPACE constants are defined in Validate class.
if( !$validate->string( $username, array('format'=>VALIDATE_ALPHA . VALIDATE_NUM . VALIDATE_SPACE ) ) )
{
//throw some username error
}
//validate email
if( !$validate->email( $email ) )
{
//throw some email error
}
//validate age, only numbers between 0 and 100 are allowed
if( !$validate->number( $age, array( 'min'=>0, 'max'=>100 ) ) )
{
//throw some age error
}
* MySQL: mysql_real_escape_string()
* PostgreSQL: pg_escape_string()
* SQLite: sqlite_escape_string()
راه ØÙ„ خوب دیگری Ú©Ù‡ Øتما باید ذکر گردد استÙاده از PDO است كه در اينجا مجالي براي Ø´Ø±Ø Ø¢Ù† نیست Ùˆ توضیØاتی در این زمینه را Ù…ÛŒ تونین در
http://ir2.php.net/pdo
Ùˆ
http://www.devshed.com/c/a/PHP/Using...ects-in-PHP-5/
مشاهده کنید مورد سوم Ú©Ù‡ شخصا شدیدا اون رو توصیه Ú©Ù‡ نه دستور Ù…ÛŒ دهم استÙاده از DAL هاست كه شخصا پيشنهادم PEAR::MDB2 هست اما هر سه گزينه زير قابل تامل Ùˆ بدرد بخور هستند
AdoDB: http://adodb.sourceforge.net/
PEAR::MDB2: http://pear.php.net/package/MDB2
Zend_Db: http://framework.zend.com/manual/en/zend.db.html
Comment