سلام دوستان، امیدوارم خوب باشید.
اول ممنونم از همه کسانی که دانش خود را با دیگران تقسیم میکنند، بدون شَک کار پر ارزشی است.
دوم هم اینکه اگر زمان پاسخ به این تاپیک تمام شده و من دیر رسیدم یا موضوع تکراری بیان میکنم من را ببخشید.
قبل از اینکه در مورد امنییت صحبت کنیم باید بدانیم که امنییت یعنی چه؛ امنییت مجموع قدمهایی است که ما برای محافظت از اشخاص یا داراییهای خود، در برابر صدمات و آسیبها بر میداریم.
در اینجا ما میخواهیم از رمزهای عبور کاربران سایت خود محافظت کنیم. همانطور که فیلسوف بزرگ آلمانی گفته : به اندارهی آدمهای روی زمین، راه حل برای انجام کارها وجود دارد و هیچ راهی بر راه دیگر تقدم نداره.
تا به حال گزارشی مبنی بر شکست شدن الگوریمهای MD5 و SHA1 داده نشده. اما میدانیم که کتابخانههای بسیاز بزرگی وجود دارد که میلیونها رمز Hash شده را شامل میشوند و در کسری از زمان هکرها میتوانند هزاران رمز را روی یک سیستم ورود امتحان کنند.
البته ما (همهی ما برنامه نویسان) میدانیم که نباید اجازه دهیم کاربر بتواند مثلاً بیش از 5 بار برای ورود با یک Username مشخص رمز وارد کند. خوب اینطوری امکان استفاده از کتابخانههای آماده هم کم میشود.
اما گر به هر دلیلی هکرها به پایگاه دادهی ما دسترسی پیدا کردند چی!؟ اینجاست که الگوریتمهای رمز نگاری به کمک ما میآیند.
حتماً میدانید یکی از فلسفههای یونیکس (Unix) و سیستم عاملهای شبه یونیکس (مثل Linux) سختتر کردن کارها برای محافظت بیشتره. حرف لینوکس شد بد نیست اضافه کنم که؛ هستهی لینوکس به صورت پیش فرض از MD5 برای ذخیره سازی رمزها در /etc/shadow استفاده میکنه و البته از الگوریتمهای زیر هم پشتیبانی میکنه :
MD5
blowfish
eksblowfish
SHA-256
SHA-512
سیستم عامل Ubuntu از نسخهی 12.04 به بعد از SHA-512 استفاده میکنه (فکر کنم CentOS هم همینطور). تا جایی هم که من اطلاع دارم گوگل هم از یک الگوریتم پیچیده بر اساس زمان استفاده میکنه.
تا اینجا امیدوارم متوجه شده باشید که هیچ کدام از الگوریتمهای ذکر شده شکسته نشدند. اما برخی از آنها منسوخ شده.
اما من به عنوان یک برنامه نویس PHP نمیتونم از خیره استفاده از MD5 بگذرم، چرا؟ سرعت فوق العادهای داره و خیلی ساده کار میکنه. ولی بر اساس فلسفه یونیکس کمی سختترش میکنم
hash('md5', '123456');// result = e10adc3949ba59abbe56e057f20f883e
hash_hmac('md5', '123456', 'my_salt');// result = 9e3f96127058d20980ecd1fb304208cd
خوب معلوم که کد دوم کار را برای هکرها سختر میکنه، پس بهتره چون ما با استفاده از یک سری کاراکتر اضافی ، تغییری در الگوریتم ایجاد میکنیم. اگر my_salt را تغییر دهیم نتیجه هم تغییر میکند. به این میگویند Salt.
همیشه استفاده از Salt در هر الگوریتمی بهتر از اسفاده نکردنه بخصوص برای جلوگیری از حملات Rainbow table (در ادامه بیشتر توضیح میدم).
البته استفاده از MD5 و SHA1 برای رمزهای عبور پیشنهاد نمیشه (من دهها مقاله خواندم و همه به دلیل منسوخ شدن نه شکسته شدن، استفاده از این الگوریتمها را پیشنهاد نکردهاند)
در مورد الگوریتمهای SHA هم باید عرض کنم که SHA1 از سال 2001 عرضه شد و تا سال 2005 مورد استفاده وسیع قرار میگرفت، اما خطاهایی در الگوریتم ریاضی آن پیدا شد که احتمال شکسته شدن آن را میداد (گرچه هنوز شکسته نشده).
برای همین سال 2005 آژانس امنیت ملی آمریکا SHA2 را منتشر کرد که شامل الگوریتمیهای 256 و 512 بایتی بود.
تا جایی که من اطلاع دارم SHA-512 در سیستمهای 64بیتی ، سریعتر از SHA-256 کار میکنه (نیاز به منبع و آزمایش دارد)
یکی از توابع خویی که در PHP میتوانید استفاده کنید Crypt است. Crypt یک Utility Software (برنامه کمکی) جهت رمز نگاری است که برای Unix طراحی شده، باید ذکر کنم این برنامه جهت بهبود الگوریتمی که توسط استاد دنیس ریچی (خالق زبان C و سیستم عامل Unix) نوشته شده بود ساخته شد، روحش شاد.
الگوریتم قدرتمند دیگر Blowfish است که با Crypt ادقام میشود. Blowfish سال 1993 ساخته شده و تا امروز هیچ انسان و نرم افزاری قادر به شناسایی و شکست آن نشده.
مثالی میزنم اما روشهای بهتر و بیشتر را در گوگل پیدا کنید.
/**
* Password Hash
*
* @param string
* @return string
*/
function pass_hash($input){
$salt = '';
$salt_chars = array_merge(range('A','Z'), range('a','z'), range(0,10));
for($i=0; $i < 22; $i++)
{
$salt .= $salt_chars[array_rand($salt_chars)];
}
return crypt($input, sprintf('$2a$%02d$', 8) . $salt);
}
/**
* Password Check
*
* @param string
* @param string
* @return bool true on success/false on failure
*/
function pass_check($pass_entered, $saved_hash_pass){
if(crypt($pass_entered, $saved_hash_pass) == $saved_hash_pass){
return true;
}else{
return false;
}
}
$saved_hash_password = pass_hash('123456');
$check = pass_check('123456', $saved_hash_password);
if(true == $check){
echo $saved_hash_password . '<br>';
}else{
echo 'Invalid password';
}
توضیح الگوهای دیگر خارج از حوصله من و شماست اما میتوانید در مورد آنها هم تحقیق کنید.
و اما نکات مهم دربارهی SALT:
در بالا برای دوستان تازه کار Salt را توضیخ دادم. در حملات Rainbow Table الگوریتمهای ضعیف به راحتی شکسته میشوند. برای همین Salt (رشتهی تصادفی که ما ایجاد میکنیم) مقاومت در برابر این حملهها را بیشتر میکند.
شاید شما هم (مثل من در گذشته) از رشتهای مانند زیر برای Salt استفاده میکنید :
$L+/F%5F:!QFpwu)
WPA2 که برای بیشتر مودمها استفاده میشود از کاراکترهایی مانند !@#$ و ... استفاده میکند. بیشتر نرمافزارهای شکستن رمز عبور مودمها نمیتوانند این کاراکترها را پیدا کنند، حتی اگر بتوانند ار الگوریتمهای موجود برای پیدا کردن رمز بهینه استفاده کنند، پیدا کردن هر کاراکتر حداقل 6 ماه وقت لازم دارد. پس به نظر نمیآید کسی بتواند به این سادگیها رشتهی فوق را حدس بزند، البته که منظور من اساتید و دانشجویان رشتهی رمز نگاری در دانشگاه هاروارد نیست!
ولی میتوانیم خیلی ساده راه را حتی برای رمز شناسان سختتر کنیم. برای این کار از توابع OpenSSL استفاده میکنیم.
if(function_exists('openssl_random_pseudo_bytes'))
{
$my_salt = openssl_random_pseudo_bytes($length = 20, $strong);
if(true === $strong){
return $my_salt;
}
}
تابع فوق یک رشتهی 20 کاراکتری، غیر قایل حدس زدن ایجاد میکند (نتیجه خروجی قابل چاپ نیست، امتحان کنید و ببینید). البته باید اضافه کنم که این تابع سرعت زیادی ندارد و خوب قرار هم نیست در لحظه دهها بار استفاده شود.
ترکیب Salt شما با نتیجهی کد فوق میتواند Salt بسیار قویای ایجاد کند.
اما یک نکته! میخواهیم برای تمام کاربران سایت از یک Salt استفاده کنیم!؟ خوب اگر Salt ما به هر دلیل شکسته شد تمام رمزها به خطر میافتد!!!
شاید بهتر باشد برای هر کاربر یک Salt اختصاصی تولید کنیم و در پایگاه داده ذخیره کنیم. خوب این کار خوبی است اما پایگاه داده ما را سنگینتر میکند، برای همین باید تمام جوانب را در نظر بگیریم.
از طرفی ما Salt ها را در پایگاه داده ذخیره میکنیم و فرض کردیم پایگاه ما به دست هکرها افتاده است... پس باز هم رمزها را از دست میدهیم!
برای حل این مشکل باید از الگوهای Encryption و Decryption برای نگهداری Salt ها استفاده کنیم (پیشنهاد میکنم در این مورد بیشتر تحقیق کنید).
یا حتی ار یک Salt از قبل ساخته شده که فقط در فایل سیستم نرم افزار ما موجود است، استفاده کنیم و آن را با Salt کاربر ترکیب کنیم، هکرها معمولاً نمیتوانند در یک لحظه هم به فایل سیستم هم به پایگاه داده دسترسی پیدا کنند، اگر هم دسترسی پیدا کردند که اصلاً توابع ما فرقی نداره چی باشه ;)
در انتها باز تکرار میکنم؛ به اندازه آدمهای روی زمین راه برای انجام کارها وجود داره. از هوشی که همهی ما انسانها در اختیار داریم استفاده کنید.
امیدوارم دانستههای من به شما کمک کنه و سایتهای مطمئنی بسازید.
موفق باشید.