در حال بارگذاري
دسته بندی موضوعی
پنل كاربر
خوش آمديد مهمان، براي استفاده از كليه امكانات سايت و ثبت نام در دوره ها ابتدا بايد وارد شويد، براي ورود اينجا را كليك كنيد.

اگر تاكنون ثبت نام نكرده ايد اينجا را كليك كنيد.
پشتیبانی آن لاین
تبليغات
آمار و اطلاعات
آمار بازخواني صفحات:



افراد آن لاين: ۱۲
تعداد كاربران: ۷۹
تعداد كالاها: ۱
تعداد مقالات / مطالب: ۹۵
تعداد مجموعه های آموزشی: ۱۲

امروز: جمعه ۱۹ شهريور ۱۳۸۹
مصادف با: September 10 2010
هش (Hash) کردن کلمات عبور در PHP www.mfeas.com >> هش (Hash) کردن کلمات عبور در PHP


هش (Hash) کردن کلمات عبور در PHP



از روز اول که وبلاگم رو راه انداخته بودم ، همان طور که تو تیتر و تگش هم هست ، هدفم تا حدود زیادی نوشتن در مورد PHP بود ، ولی تقریبا می شه گفت به غیر از کارهایی که در مورد وردپرس انجام دادم و بلاگ کردم دیگه مطلبی در مورد PHP ننوشتم ، تصمیم گرفتم یه سری مقاله در مبحث “امنیت در برنامه نویسی با PHP” ترجمه کنم یا بنویسم تا هم ضعف هایی که تو این زمینه میون برنامه نویس های ایرانی وجود داره بر طرف بشه و هم کم کم وبلاگم هم رنگ و بوی PHP بگیره.

در این مقاله سعی داریم مبحث به رمز درآوردن یک طرفه کلمات عبور(Password Hashing) در PHP را مورد بحث قرار دهیم، موضوعی که عموما توسط بسیاری از نوآموزان PHP نادیده گرفته می شود.در بسیاری از نرم افزارهای (ضعیفی) که با PHP نگاشته می شوند اطلاعات اعضا (User Profiles) به صورت متن ساده (Plain Text) در بانک اطلاعاتی ذخیره می گردد. هش کردن کلمات عبور راهی است برای یه رمز در آوردن(Encrypt) کردن کلمات عبور قبل از ذخیره سازی آن ها در بانک اطلاعاتی تا هنگام دسترسی افراد غیر مجاز به بانک اطلاعاتی ، میزان خسارت کمتر گردد. هش کردن به هیچ وجه روش جدیدی به حساب نمی آید و از مدتها قبل در سیستم های مبتنی بر UNIX برای ذخیره سازی کلمات عبور استفاده می شده است. در این مقاله سعی خواهیم کرد تا با بیان مفاهیم هش ، راه های عملی استفاده از آن در PHP (و MySQL) را برای دخیره کلمات عبور در قالب مثال هایی تشریح کنیم.

پیش گفتار
هنگام مطالعه این مقاله مشاهده خواهید نمود که ما از روشی به نامه SHA-1(Security Hashing Algorithm 1) برای هش کردن استفاده خواهیم کرد. تا هنگام نگاشته شدن این مقاله گروهی از محققان - Xiaoyun Wang, Yiqun Lisa Yin, Hongbo Yu - نشان داده اند که SHA-1 ضعیف تر از آن چیزی است که به نظر می رسیده است، به این معنی که هم اکنون برای موارد خاص مانند امضاهای دیجیتالی ، الگوریتم های قوی تری مانند SHA-256 و SHA-512 توصیه می گردد ولی برای هش کردن کلمات عبوردر برنامه های امروزی SHA-1 هنوز سطح امنیت بسیار خوبی را فراهم می کند.

هش چیست؟

هش (Hash, Hash Code, Digest, Message Digest هم نامیده می شود) را می توان به صورت اثر انگشت دیجیتالی یک داده در نظر گرفت. با این روش شما می توانید رشته ای اندازه-ثابت (fixed length) از یک داده به دست آورید که با روش های ریاضی به صورت "یک طرفه" رمزنگاری شده است. کشف رشته اصلی از رشته هش آن (عملیات معکوس) به صورت کارا تقریبا غیر ممکن است. نکته دیگر اینکه هر داده یک رشته هش شده کاملا منحصر به فرد ایجاد می کند( احتمال یکی شدن رشته های هش دو رشته متفاوت در الگوریتم MD5 یک در ۳/۴۰۲۸۲۳۶۶۹۲۰۹۳۸۴۶۳۴۶۳۳۷۴۶۰۷۴۳۱۷۷e+38 می باشد. این خواص ، هش کردن را به روشی کارا و ایده آل برای ذخیره سازی کلمات عبور در برنامه های شما تبدیل می کند. چرا؟ برای این که حتی اگر یک نفوذگر(Hacker) بتواند به سیستم و بانک اطلاعاتی شما نفوذ کند و بخشی از اطلاعات شما را به دست آورد (شامل کلمات عبور هش شده) نمی تواند کلمات عبور اولیه را از روی آن ها بازیابی کند.

با این روش چگونه اعضا را شناسایی کنیم ؟
تا کنون نشان داده ایم که بازیابی کلمه عبور اصلی از روی رشته هش تقریبا غیر ممکن است ، خب چگونه برنامه های ما تشخیص دهند که کلمه عبور وارد شده توسط کاربر صحیح است ؟ به سادگی ! با تولید رشته هش کلمه عبور وارد شده توسط کاربر و مقایسه آن با رشته هش ذخیره شده در رکورد بانک اطلاعاتی مربوط به کاربر می توانید متوجه شوید که آیا دو رشته با هم برابرند یا نه. بگذارید با ذکر یک مثال این بحث را ادامه دهیم.

ثبت نام اعضا و بازبینی کلمات عبور
در طی پروسه ثبت نام ، کاربر جدید کلمه عبور انتخابی خود را در اختیار برنامه ما قرار می دهد(ترجیحا با بازبینی - Verification - و در یک جلسه امن). این کار توسط تکه کدی مانند زیر انجام می گیرد، توجه کنید که نام های کابری و کلمات عبور را در بانک اطلاعاتی ذخیره می کنیم.

اسكريپت:
<?php
/* Store user details */
$passwordHash = sha1($_POST['password']);
$sql = 'INSERT INTO user (username,passwordHash) VALUES (?,?)';
$result = $db->query($sql, array($_POST['username'], $passwordHash));
?>

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

اسكريپت:
<?php
/* Check user details */
$passwordHash = sha1($_POST['password']);
$sql = 'SELECT username FROM user WHERE username = ? AND passwordHash = ?';
$result = $db->query($sql, array($_POST['username'], $passwordHash));
if (
$result->numRows() < 1)
{
   
/* Access denied */
   
echo 'Sorry, your username or password was incorrect!';
}
else
{
   
/* Log user in */
   
printf('Welcome back %s!', $_POST['username']);
}
?>

انواع هش
انواع مختلفی از الگوریتم های قوی هش کردن برای استفاده در برنامه های کاربردی موجود هستند، محبوب ترین آنها که مورد استفاده برنامه نویسان هستند MD5 و SHA-1 می باشند. سیستم های قدیمی تر از DES(Data Encryption Standard) استفاده می کردند. این روش ۵۶ بیتی دیگر یک روش قوی هش کردن محسوب نمی گردد.

در PHP شما می توانید رشته هش را با استفاده از توابع md5() و sha1 تولید کنید. md5() یک رشته هش ۱۲۸ بیتی (۳۲ کاراکتر هگزادسیمال) برمی گرداند در حالیکه sha1() یک رشته هش ۱۶۰ بیتی (۴۰ کاراکتر هگزادسیمال) را بر می گرداند.

اسكريپت:
<?php
$string
= 'PHP & Information Security';
printf("Original string: %sn", $string);
printf("MD5 hash: %sn", md5($string));
printf("SHA-1 hash: %sn", sha1($string));
?>

این کد خروجی زیر را تولید می کند:

Original string: PHP & Information Security
MD5 hash: 88dd8f282721af2c704e238e7f338c41
SHA-1 hash: b47210605096b9aa0129f88695e229ce309dd362

در MySQL شما می توانید رشته هش را مستقیما و توسط توایع درونی md5() ، password() و یا sha1() تولید کنید. password() تابعی است که توسط خود MySQL برای سیستم تایید اعضایش یه کار می رود. این تابع یک رشته ۱۶ بایتی (۱۲۸ بیتی) - در MySQL قبل ازنسخه ۴/۱ - و یک رشته ۴۱ بایتی ( ۳۲۸ بیتی) بر پایه الگوریتم SHA-1 دوگانه - در MySQL 4.1 به بالا - تولید می کند. md5() از نسخه ۳/۲۳/۲ به MySQL اضافه گردید و sha1() در نسخه ۴/۰/۲ اضافه شد.

mysql> select PASSWORD( 'PHP & Information Security' );
+------------------------------------------+
| PASSWORD( 'PHP & Information Security' ) |
+------------------------------------------+
| 379693e271cd3bd6 |
+------------------------------------------+
1 row in set (0.00 sec)
mysql> select MD5( 'PHP & Information Security' );
+-------------------------------------+
| MD5( 'PHP & Information Security' ) |
+-------------------------------------+
| 88dd8f282721af2c704e238e7f338c41 |
+-------------------------------------+
1 row in set (0.01 sec)Note: Using MySQL's password() function in your own applications isn't recommended - the algorithm used has changed over time and prior to 4.1 was particularly weak.

شما ممکن است ترجیح دهید تا از MySQL برای تولید رشته هش در برنامه های خود استفاده نمایید. مثلا در مثال این مقاله :

اسكريپت:
<?php
/* Store user details */
$sql = 'INSERT INTO user (username, passwordHash) VALUES (?, SHA1(?))';
$result = $db->query($sql, array($_POST['username'], $_POST['password']));
?>


نقاط ضعف
از دیدگاه امنیتی ، ذخیره کردن رشته های هش کلمات عبور به صورت تنها در بانک اطلاعاتی کافی است تا کار یک نفوذگر را ده ها برابر مشکل تر کند. حال بگذارید ببینیم یک نفوذگر پس از دسترسی به این رشته های هش شده چه تلاش هایی برای بازیابی آن ها می کند، آیا او می تواند کلمات عبور اصلی را بازیابی کند ، یا خیر؟

او ابتدا می تواند با مشاهده جدول اعضا و با پیدا کردن رشته های هش مشایه حساب هایی که دارای کلمات عبور یکسان هستند را بیابد! البته این روش تا زمانی که او کلمه عبور هیچ کدام از اعضا را نداند مفید نیست و خطری را ایجاد نمی کند. روش معمول برای بازیابی رشته اصلی از رشته هش شده شکستن (Crack) کردن - یا به عبارت دیگر brute forcing - می باشد. با استفاده از این روش نفوذگر رشته های هش تمامی عباراتی که احتمال می دهد به عنوان کلمه عبور به کار برده شوند - مثلا با استفاده از یک دیکشنری لغات - را تولید می کند و با مقایسه آن ها با مقادیر ذخیره شده در بانک اطلاعاتی اقدام به یافتن کلمات عبور می نماید.

رایانه های پیشرفته امروزی توانایی تولید رشته های هش MD5 و SHA-1 را به صورت بسیار سریع دارا می باشند - در بعضی حالات با سرعت هایی در حدود چند هزار در ثانیه - . رشته های هش می توانند برای تمامی کلمات یک دیکشنری تولید شوند(حتی با احتساب حالت های متفاوت حرفی و عددی) . با این که کلمات عبور مناسب و طویل سطح امنیتی خوبی را در برابر چنین حملاتی فراهم می کنند، شما نمی توانید مطمئن باشید که کاربران شما همواره از چنین مواردی آگاه باشند.

روشمان را بهبود دهیم
نقاط ضعفی که در مورد هش کردن بیان گردیدند با اضافه کردن تغییر کوچکی در الگوریتم هش کردن به راحتی قابل برطرف کردن می باشند. می توانیم قبل از تولید هش ، یک رشته تصادفی با اندازه از پیش تعیین شده تولید کنیم و آن را به ابتدای کلمه عبور خود اضافه نماییم(این رشته را salt می نامیم). با اضافه شدن این رشته که به اندازه کافی تصادفی و به اندازه کافی طویل می باشد ، رشته هش نهایی هر بار که تابع را اجرا می کنیم منحصر به فرد خواهد بود و با دفعات قبلی فرق خواهد داشت. بدیهی است که این رشته salt نیز باید در بانک اطلاعاتی اعضا ذخیره گردد ، ولی این تنها به معنی اضافه شدن چند کاراکتر به اندازه فیلد مورد نظر است.

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

اسكريپت:
<?php
define
('SALT_LENGTH', 9);
function
generateHash($plainText, $salt = null)
{
    if (
$salt === null)
    {
       
$salt = substr(md5(uniqid(rand(), true)), 0, SALT_LENGTH);
    }
    else
    {
       
$salt = substr($salt, 0, SALT_LENGTH);
    }

    return
$salt . sha1($salt . $plainText);
}

?>Note: The function above is limited in that the maximum salt length is 32 characters. You may wish to write your own salt generator to overcome this limit and increase the entropy of the string.

هنگام فراخوانی generateHash() با استفاده از تنها یک آرگومان(کلمه عبور) یک رشته تصادفی تولید شده و به عنوان رشته salt استفاده می گردد. رشته تولید شده که تشکیل شده از رشته salt و رشته هش شده است در بانک اطلاعاتی ذخیره می گردد. هنگام بررسی ورود کاربر ، پروسه کاملا متفاوت است زیرا شما رشته salt را می دانید. - دقت کنید از آن جایی که طول رشته salt ثابت است ، پس از دریافت اطلاعات کاربر از بانک اطلاعاتی با یک بار استفاده از تابع substr می توانید رشته salt را بیابید - این رشته salt به عنوان پارامتر دوم به همراه کلمه عبور ارسالی کاربر به تابع generateHash() فرستاده می شود و سپس عمل مقایسه صورت می پذیرد.

با استفاده از salt احتمال یکی شدن رشته های هش کابران در صورت یکی بودن کلمات عبورشان در بانک اطلاعاتی از بین می رود.

استفاده از دیکشنری برای حمله نیز دیگر کارایی نخواهد داشت، زیرا نفوذگر باید برای هر رکورد در بانک اطلاعاتی تمامی رشته های هش دیکشنری خود را دوباره محاسبه کند!






تبلیغات


خروجی PDF این مقاله | خروجی word این مقاله | پرینت | ارسال این مطلب به دوست | تاریخ افزودن: | آخرین تغییرات انجام شده:
نظرات کاربران

هیچ نظری یافت نشد.


لطفا نظر خود را بنویسید:

نام:

حداکثر سایز 1000 کاراکتر

امتیاز این مطلب: