یک عدد جونیور علاقه مند به حوزه امنیت :)
رمزنگاری مقدماتی : Password Storage - Salt - Pepper
در این مطلب میخوایم به نحوه ذخیره سازی پسورد بپردازیم ، وقتی میگیم ذخیره پسورد منظورمون بیشتر هشی هست که سمت Web Application هست و سمت Back-end ذخیره میشه ، و از اونطرف چون اکثر وب اپلیکیشن ها لینوکسی هستن پس یه جورایی ذخیره پسورد توی لینوکس رو هم مورد بررسی قرار دادیم ، ولی جریان برای ویندوز کلا فرق داره که توی سری پیشرفته بررسیش میکنیم
وقتی شما مکانیزم احرازهویت پسوردی ای پیاده سازی میکنید در جایی ، مثلا سمت وب اپلیکیشن ، مثلا ویندوز مثلا لینوکس یا هرجا ، این پسورد باید یه جا ذخیره بشه ، اگر معمولی ذخیره بشه و هکر ها بهش دسترسی پیدا کنن خیلی بد میشه :) پس میان و اونو هش میکنند و بعد ذخیره میکنن ، اینطوری وقتی مهاجم به هش ها دسترسی پیدا کنه دیگه خیلی راحت نمیتونه پسورد رو استفاده کنه
شاید بگید مثلا اگر هکر پسوردو به دست بیاره چه کار میتونه بکنه ؟
اگر یه هکر رو بدست بیاره میتونی بعدا به سیستم راحت تر دسترسی بگیره یا روی ماشین های دیگه دسترسی بگیره و حملات دیگه که توی دسته شبکه قرار میگیرن ، از اون طرف یه قاعده ساده رو ما نباید یادمون بره ، کاربر ها اکثرا یک پسورد رو برای چندین جا استفاده میکنن و اگر یه جا پسوردشون لو بره و شما اون پسورد رو در بقیه جاها استفاده کنید ، میتونید به سایر حساب های مهاجم هم دسترسی بگیرید
سر همینه که مقوله ذخیره پسورد خیلی مهمه ، سازوکار و راه همون هشینگه ولی یه تفاوتایی داره که میخوایم بررسی کنیم :
فرض کنید یه سایتی داریم و توش 5 تا یوزر ثبت نام کردن ، سایت میاد و پسورد هر یوزر رو به صورت هش ذخیره میکنه ، توی این جدول من به صورت ساده بهتون نمایش میدم که درک کنید بعد میریم کد هاشم نشون میدم:
وقتی که کاربر ها میخوان وارد شن اول یوزر و بعد پسورد رو تایپ میکنن و سایت هش میگیره از پسوردی که تایپ شده و با هشی که توی دیتابیس بوده مقایسه میکنه ، اگر اوکی بود مجوز ورود رو بهشون میده
حالا اگر یه مهاجم بیاد و یه سایتی رو بزنه که هش هاش طبق عکس 1 باشه ، خب میره و به سایت های انلاین میده که کرکش کنن (ما در این مثال از MD5 استفاده کردیم) و راحت پسوردا رو میریزه بیرون :
همونجور که شاهدید مثل کره کرک شدن و مشکل اینجاست که کاربر مسعود و مجید پسورداشون یکیه ، و این مشکل ایجاد میکنه :)
پسورد ها چگونه کرک میشن ؟
پسورد های هش شده به این صورت کرک میشن که اول مهاجم میاد یه لیست از پسورد هایی که فکر میکنه کاربرها میسازن رو بدست میاره ، حالا یا حدس میزنه یا با هر حمله ای این لیستو بدست اورده ، بعد این هارو هش میکنه و توی یه جدول ذخیره میکنه به همراه پسورد اصلی ، اون جدول اسمش Lookup Table هست ، و وقتی مهاجم یه هش جدید بدست میاره ، میاد و این هش رو مقایسه میکنه با کل اون Lookup Table و اگر هش نظیرشو پیدا کنه چون پسورد خامشم هست دیگه راحت پسوردو به دست میاره ، و سایتی که بالا ازش استفاده کردیم هم مکانیزم کاریش به همین صورته
Pepper چیست ؟ :
امدن گفتن خب ، ما بیاییم یه چیز دیگه هم بغل پسورد بزاریم که وقتی هش میگیریم کار رو برای مهاجم سخت تر کنیم و دیگه موقع کرک پسورد ، Lookup Table ها کارساز نباشن ، امدن توی خود کد وب اپلیکیشن یک عبارت ثابت (Pepper) اضافه کردن که وقتی شما ثبت نام میکنید و پسوردتون میخواد برای اولین بار هش بشه ، پسوردتون+اون مقدار ثابت باهم هش میشه (اصطلاحا به نوشتن یک چیز داخل کد برنامه میگن HardCode)
همونطور که مشاهده میکنید وقتی Pepper ما اضافه شد هش ها عوض شد ، حالا بریم کرکشون کنیم :
شاهد هستید که Lookup Table ها خیت میشن :)
اما کار اینجا تموم نیست ، مشکلی که پابرجاست اینه که اگر مهاجم بتونه سورس کد برنامه رو دربیاره ، به Pepper هم میرسه و میتونه Lookup Table خودشو بسازه ، عههه بد شد که
از اونور اگر مهاجم پسورد مسعودو کرک کنه ، پسورد مجیدم کرک کرده :)
Salt چیست ؟ :
آمدن گفتن ما موقع ثبت نام هرکاربر بیاییم و یه استرینگ یا رشته یا همون عبارت بهش اختصاص بدیم ، به صورت رندوم ، و موقع هش گرفتن با اون هش گرفته بشه :
و همونطور که شاهدید ما میرسیم به جدول بالا ، وقتی مهاجم به هش ها برسه ، بر فرضی که به کد های وب اپلیکیشن هم دسترسی گرفته باشه ، یه زمان زیادی طول میکشه که بیاد Lookup Table بسازه، یعنی یه لیست پسورد بلـــــــــــــــــند ، و Pepper و Salt بعدش و شروع کنه به ساخت پسورد !
نکته ای که باید تاحالا متوجه میشدید اینه که وقتی Salt پاش به میون امد ، هش پسورد مجید و مسعود عوض شدن ، با وجود اینکه پسورداشون یکی بوده :)
الگرتیم های ذخیره پسورد (PBKDF2 - bcrypt - scrypt - Argon2) :
نکته آخر در باب ذخیره سازی پسورد بحث الگریتم هشی هست که مورد استفاده واقع میشه ، الگریتم های Hahing ای که تاحالا معرفی کردیم خیلی سریع هستن و اگر با اون ها پسورد رو ذخیره کنیم ، مهاجم موقع کرک خیلی خوشبحالش میشه ?
بجاش ما میاییم الگریتمی رو استفاده میکنیم که همونطوری باشه ولی خیلی کُند تر باشه ، که وقتی مهاجم خواست Lookup Table بسازه دهنش آسفالت بشه ?
الگریتم های ذخیره سازی پسورد عملیات هشی که مثلا الگریتم MD5 یا SHA2 یکبار یا دوبار انجام میدن رو 1000 بار انجام میده ، و اینطوری باعث میشه حدود دو یا شایدم سه ثانیه فرایند هش کردن طول بکشه ، ولی امنیتی که میده خیلی زیاده ، چرا ؟ فرض کنید مهاجم یک میلیون پسورد داره و میخواد با الگریتم MD5 بیاد و Lookup Table بسازه که ساخت هر پسورد حدودا نیم ثانیه طول میکشه ، چقدر طول میکشه ؟ 140 ساعت حدودا ، حالا اگر با الگرتیم Argon2 اینکارو بکنه چون هر پسورد ساختش 3یا2 ثانیه طول میکشه و به عبارتی 830 ساعت کارش طول میکشه ، یعنی تقریبا 6 برابر بیشتر کارش طول میکشه !!!
کد هایی که میزارم رو باهم ببینیم :
ما میاییم برای مثال توی PHP یه مکانیزم ذخیره سازی پسورد پیاده سازی میکنیم ، خط دوم ما Pepper رو مشخص کردیم و طولشم تو خط سوم معلوم کردیم ، خط 4 و 5 ما Salt مون رو به وسیله توابع درونی خود PHP پیاده سازی کردیم
وقتی کاربر میخواد وارد شه ، پسوردشو وارد میکنه و ریخته میشه توی متغییر خط 13 ، خود PHP براش یه Salt میسازه تو خط 4و 5 و میریزش تو متغییر خط 15 ، تو خط 7 پسورد کاربر با Pepper و Salt پردازش میشه و توسط الگریتم قدرمتند آرگون 2 رمز میشه و ریخته میشه توی متغییر خط 17
حالا یوزر میخواد لاگین کنه ، وقتی وارد سایت میشه و پسورد رو میزنه توی متغییر خط 19 ریخته میشه و بعد تو خط 21 وارد میشه و وارد تابع شرطی خط 23 میشه ، بعد میره توسط تابع خط 10 پردازش میشه ، توی خط 10 پسورد ورودی کاربر با Salt و Pepper هش میشه و در مقابل پسورد هش شده ذخیره شده از قبل مقایسه میشه ، اگر اوکی بود که احراز میشه ، اگر نبود پیغام Invalid براش میاد
ساختار پسورد ذخیره شده و کار با ابزار Openssl :
بزارید با ابزار قدرتمند Openssl یک پسورد بسازیم که ببینید وقتی توی دیتابیس سمت Back-end ذخیره میشه به چه صورت هست :
hpn# openssl passwd -1
وقتی ما passwd رو تایپ کردیم یعنی ما قراره بهت یه پسورد بدیم و اونو برامون با الگرتیم 1 که میشه MD5 هش کن ، و از ما پسورد رو میپرسه و به این صورت نشون میده :
$1$7bgFW5iI$XmRSlDK3Wd9DkdUiVoEuB0
دقت کنید که این استرینگ سه تا علامت دلار "$" داره ، بین دوتای اول عبارت 1 قرار گرفته که میگه الگریتم استفاده شده MD5 عه ، بین علامت دلار دوم و سوم هم مقدار Salt ما قرار گرفته ، چون مشخص نکردیم رندوم زده برامون و از دلار سوم به بعد پسورد هش شده رو گذاشته برامون ، حالا اگر بخوایم Salt رو دستی بزاریم :
hpn# openssl passwd -1 -salt Virgool
$1$Virgool$macUQAD1nNOHf.yaRZ3gU/
ما با سویچ salt- امدیم و مقدار سالت دلخواهمونو وارد کردیم ، این روش اصلا توصیه نمیشه ، چرا؟ چون بالاتر گفتم که Salt باید رندوم باشه ، و اینطوری انگار داریم Pepper میدیم ، از اونطرف اگر دستور رو اینطوری زده باشید خود شل ازتون پسورد رو میگیره که امن تره ، ولی اگر پسورد رو خودتون بهش بدید به این صورت :
hpn# echo virgool | openssl passwd -1 -stdin -salt Virgool
$1$Virgool$Nie3lsHCp.GEugMtvYDHM0
میتونیم با stdin- بهش ورودی بدیم ولی نکته جالبش اینه که این روش اصلا امنیت نداره ، چون اگر مهاجم به شل شما دسترسی بگیره با یه دستور history ساده هم پسورد رو در میاره هم Salt رو :)
اگر یه هش بهتون رسید و نفهمیدید چ هشیه میتونید از سایت های زیر استفاده کنید :
یک مثال عملی و تازه از هک شدن دیتابیس یکی از سایت های ایرانی و عدم استفاده طراحان از Pepper و Salt نتیجه اون :
پایگاهدادهای حاوی بیش از 2 میلیون خط مروبط به قاصدک 24، سامانه خرید اینترنتی بلیط هواپیما قطار اتوبوس و رزرو هتل نشت پیدا کرده ، و شما به هش های این ها نگاه کنید:
برای مثال به بالای عکس قاصدک نگاه کنید ، هش خانم فاطمه حسین نژادیان رو تست میکنیم ببینیم پسوردش چیه :
راحت تر از اون چیزی که فکر کنید کرک شد :) ، این یک فاجعس و شما فکر نکنید این مطالبی که میخونید چون سادست بدون کاربرده ، اتفاقا رعایت نکردنشون همچین فاجعه هایی به بار میاره !
در مطلب بعدی سراغ رمزنگاری میریم و تازه کارمون شروع میشه :) هر سوال یا انتقادی بود در خدمتم ، یاعلی
مطلبی دیگر از این انتشارات
رمزنگاری مقدماتی : بررسی امنیت پروتوکول های شبکه
مطلبی دیگر از این انتشارات
رمزنگاری مقدماتی : رمزنگاری نامتقارن یا Asymmetric Encryption
مطلبی دیگر از این انتشارات
رمزنگاری مقدماتی :رمزنگاری منحنی بیضوی یا Elliptic-Curve