ببینید، Salt (نمک) یک رشته ثابت هست که به عبارت اصلی اضافه میشه (در مکان مشخص مثل اول، آخر، پنجمین کارکتر و...) و بعد، رشته Hash میشه تا ازطرفی امکان پیدا شدن رمز توی سایتهایی که بهشون اشاره کردم، کمتر بشه و ازطرف دیگه، درصورت پیدا شدن، پسورد اصلی لو نره. البته اگه چند تا از رمزها پیدا بشه، اونوقت میشه به راحتی Salt رو حدس زد که چیه و از رشته تولیدشده حذف کرد و رمز اصلی کاربر رو بدست آورد. بنابراین، روش دیگری به نام Pepper (فلفل) ابداع شد که توی این روش، رشته ای که به عبارت اضافه میشه، تصادفی هست و همراه رمز توی دیتابیس (توی یک فیلد جداگانه توی همون رکورد کاربر) ذخیره میشه تا بعداً موقع بررسی رمز، دوباره توی تولید Hash بر اساس کدی که کاربر وارد کرده بکار گرفته بشه و اگه همون رمز موجود در دیتابیس تولید شد، یعنی کاربر رمز رو درست وارد کرده. احتمال حدس زدن Pepper از Salt کمتره. البته میشه ترکیب این روشها رو هم بکار برد. روش Multiple Hashing هم خیلی ساده میگه که بجای یکبار Hash کردن، چندبار این عمل انجام بشه. این روش دو امتیاز داره: 1- احتمال پیدا شدن Hash نهایی توی سایتهای مذکور کمتر میشه و 2- سرعت تولید رمز کاهش پیدا میکنه و درنتیجه نمیشه با روشهایی مثل Bruteforce (امتحان کردن رمزهای مختلف توسط سیستمهای خودکار - مثل کاری که موقع بازکردن قفل چمدانی که رمزش رو نمیدونین انجام میدین) و... به راحتی رمز رو پیدا کرد. بگذارین یه مثال بزنم:
فرض کنید توی دیتابیس در جدول users علاوه بر فیلدهای استاندارد، یک فیلد دیگه هم برای Pepper اضافه کردیم و Salt رو هم یک رشته ثابت مثلاً
www.ncis.ir درنظر گرفتیم. بنابراین، فیلدهای جدول users میشه این:
1- id (کلید اصلی)
2- name (نام)
3- user (نام کاربری)
4- pass (رمز عبور)
5- pepper (فلفل)
حالا به تابع زیر که رمز و Pepper رو تولید میکنه دقت کنید:
PHP:
function MakeHash($value, &$pepper = NULL) {
if($pepper == NULL) {
$pepper = md5(microtime());
}
$salt = 'www.ncis.ir';
for($i = 0; $i < 1000; $i++) {
$value = md5($salt . $value . $pepper);
}
return $value;
}
این تابع، ابتدا md5 زمان جاری رو برحسب میلیونیوم ثانیه بعنوان pepper$ تعریف میکنه. بعد هم
www.ncis.ir رو توی متغیر salt$ میگذاره. حالا میاد و 1000 بار، هر دفعه salt$ و pepper$ رو دوطرف value$ (مقداری که میخوایم Hash کنیم) قرار میده و میفرسته به md5 تا Hash این رشته رو تولید کنه و خروجی رو توی value$ میگذاره. نهایتاً هم value$ رو برمیگردونه. pepper$ هم که چون با & توی تعریف تابع اومده، بصورت ارجاعی هست یعنی هر تغییری ما توی تابع روی pepper$ دادیم، بیرون از تابع روی آرگومانی که بجای این متغیر فرستادیم اعمال میشه. حالا کافیه خروجی این تابع رو توی فیلد pass دیتابیس و مقدار آرگومانی که موقع فراخوانی تابع بجای pepper$ نوشتیم رو هم توی فیلد pepper توی دیتابیس ذخیره کنیم. اینطوری موقع چک کردن رمز کاربر، اول بر اساس نام کاربری، pepper$ مربوط به اون کاربر رو از دیتابیس پیدا کرده و میخونیم و بعد، اون رو با مقداری که کاربر توی کادر password وارد کرده، همراه با pepper$ که از دیتابیس خوندیم، به همین تابع MakeHash میدیم و اگه همون pass توی دیتابیس تولید شد یعنی رمز درست وارد شده. ازطرفی چون 1000 بار Hash انجام شده، درنتیجه عملیات تولید و مقایسه رمز بجای چند میلیونیوم ثانیه (الگوریتم MD5 خیلی سریعه)، چند هزارم ثانیه طول میکشه و درنتیجه در هر ثانیه میشه یک هزارم تعداد حالت عادی، رمز امتحان کرد که این مسئله خودش باعث خنثی سازی اکثر حملات Bruteforce میشه.