به کمک هشها میتوانیم دادههای مهم را کد کنیم. hash یک رمزنگاری یکطرفه است؛ یعنی یک متن هششده را نمیتوانیم به متن معمولی برگردانیم. از این کار برای افزایش امنیت سیستم سایت و اسکریپتها استفاده میشود. در این آموزش نحوه کار و ترفندهای هش در PHP را یاد میگیریم.
همه ما در سایتهای مختلفی عضو هستیم. هر سایت اطلاعات مختلفی از ما نگهداری میکند؛ از اطلاعات شخصی مانند نام و سن و ایمیل گرفته تا اطلاعات حیاتیتری مانند رمزهای عبور!
حداقل هر چند ماه یکبار میشنویم که دیتابیس فلان سایت یا شبکه اجتماعی معروف مورد نفوذ قرار گرفته و اطلاعات تعدادی از کاربران فاش شده است. تا حالا به این مسئله فکر کردید که چرا در این هکها اطلاعات بسیار مهم مثل پسوردها کمتر منتشر میشوند؟
یکی از پاسخهای اصلی به این سؤال، هش کردن اطلاعات بسیار مهم نظر رمزهای عبور در سایتهاست. در ادامه، ابتدا با هش و فرآیند کلی آن به زبان ساده آشنا میشویم و سپس توابع هش و ترفندهایی برای افزایش امنیت سایت را مطرح میکنم.
فهرست محتوای آموزش
هش در PHP
هش کردن (هشینگ یا Hashing) یک رمزنگاری یک طرفه است. رمزنگاری اطلاعات به زبان ساده، تغییر اطلاعات به شکلی است که قابل فهم نباشد.
فرض کنید رمز عبور من در سایتی 123456
است. اگر توسعه دهنده سایت این رمز را به همین شکل در دیتابیس ذخیره کند، در هنگام هک شدن یا لو رفتن دیتابیس کاربران سایت، رمز من به راحتی قابل تشخیص است. اما اگر با یک روش خاص یا الگوریتمهای موجود، این رمز را به abcdef
تبدیل و ذخیره کند،فهمیدن آن سختتر خواهد شد.
به نظر شما رمز عبورم را چطور رمز کردم؟! لطفاً یک تناظر بین این دو رشته ایجاد کنید و سپس ادامه دهید. من در اینجا از تناظر عدد و شماره ترتیبی کاراکتر انگلیسی استفاده کردم. چیزی که احتمالاً شما هم توانستید حدس بزنید! جلوتر میبینیم که الگوریتمهای هش بسیار پیچیدهتر از این مثال عمل میکنند. 🙂
تفاوت هش با رمزنگاری
اجازه دهید قبل از ادامهی آموزش، توضیح مختصری در مورد تفاوت هش و رمزنگاری در PHP و دنیای کامپیوتر بدهم.
فرض کنید میخواهم به شما بگویم: «فردا ساعت ۵ به آموزشگاه سبز دانش بیا!» این پیام را هر کس دیگری که ببینید یا بشوند، متوجه روز، ساعت و محل قرار ما میشود. اما اگر بگویم «tf5sbdz» و این کدگذاری طبق یک قرارداد بین من و شما باشد، تقریباً هیچ فرد دیگری چیزی متوجه نمیشود!
این یک مثال خیلی ساده از رمزنگاری دوطرفه بود؛ چون اگر الگوریتم را بدانیم، از روی متن کدشده، میتوانیم به متن اصلی برسیم. اگر علاقهمندید، در آموزش روشهای رمزنگاری اطلاعات در مورد چند روش معروف و پایه برای رمزنگاری صحبت کردهام.
هشها یکطرفه هستند. یعنی هیچ وقت نمیتوان از روی متنی که هش شده، به متن غیر هش رسید!
توابع هش کردن در PHP
بیایید یک متن را در PHP هش کنیم. یادتان باشد که اگر همه دیتاهای سایت را هش کنیم، عملاً فایدهای ندارد! چرا که مثلاً اگر موجودی کیف پول را هش کنیم، دیگر نمیتوانیم به آن دسترسی داشته باشیم؛ ولی هش کردن پسورد در PHP یکی از متداولترین کارهاست.
اما چطور با هش کردن پسورد آن را اعتبارسنجی کنیم؟ پاسخ ساده است! به جای اینکه پسورد را به صورت plain text (بدون هش و معمولی) نگهداری کنیم، در هنگام ورود کاربر به سایت، رمز وارد شده را با مقدار ذخیرهشده در دیتابیس مقایسه میکنیم. اما اگر مقدار hashشده را ذخیره کرده بودیم، پسوردی که کاربر وارد کرده را هش میکنیم و دو تا hash را مقایسه میکنیم.
در حقیقت هیچگاه پسورد اصلی را در دیتابیس ذخیره نمیکنیم و به جایش مقدار هش معادل آن در PHP را نگهداری میکنیم. از این روش در ساخت فرم ورود با PHP استفاده کردهایم.
۴ تابع هش پسورد
در زبان برنامه نویسی PHP الگوریتمهای built-in مختلفی برای هش کردن اطلاعات وجود دارد. برای برخی از پرکاربردترینها نیز توابع خاصی تعریف شده که میتوانیم مستقیماً از آنها استفاده کنیم. (اگر نمیدانید تابع چیست ببینید: تابع PHP)
یکی از ویژگیهای الگوریتمهای هش این است که باید به ازای ورودیهای مختلف، خروجیهای مختلف (یکتا) تولید کنند. یعنی هیچ دو عبارت متفاوتی وجود ندارد که هش یکسان داشته باشند!
تابع md5
اولین تابع هش در PHP، تابع md5()
است. این تابع از الگوریتمی به همین نام (الگوریتم md5) برای هش کردن رشته متنی در php استفاده میکند.
<?php
echo md5("sabzdanesh");
همانطور که در تصویر بالا میبینید، هش «سبز دانش» یک رشته نامفهوم و طولانیتر از رشته اصلی است. خروجی این الگوریتم همیشه یک رشته متنی 32 کاراکتری است؛ چه ورودی یک کاراکتر باشد، چه هزار کاراکتر!
اگر کمی در توسعه وب فعالیت کنید، میشنوید که هش md5 امنیت ندارد! و همیشه بحثهایی مطرح میشود که آیا هش md5 در PHP امنیت دارد؟ واقعیت این است که این الگوریتم امنیت دارد، اما دیتابیسهای بزرگی در سطح اینترنت وجود دارد که رشتههای مختلف با هش md5 معادلشان را محاسبه کردهاند.
در حملات brute force (حمله جستجوی فراگیر) با ایجاد تناظر بین هشها، رشته اصلی پیدا میشود. (البته نه به همین سادگی!) این بحث خارج از این آموزش است؛ اما در همین حد بدانید که چنین روشهایی برای هک هش PHP وجود دارد.
در مجموع امروزه پیشنهاد میشود از md5()
براش هش کردن رشته در PHP استفاده نکنیم. به جای آن از الگوریتمهای دیگر استفاده کرده یا از ترفندهایی برای افزایش امنیت هش استفاده کنیم.
تابع crypt
این تابع از امنیت بیشتری نسبت به تابع هش قبلی برخوردار است. این تابع دو پارامتر ورودی میگیرد. البته میتوانیم پارامتر دوم را تعریف نکنیم اما در شرایط خاص! به آرگومان دوم اصطلاحاً salt گفته میشود و میتواند هر رشته دلخواهی باشد. درباره این مقدار، در قسمت افزایش امنیت هش PHP صحبت میکنم.
<?php
// create PHP Hash with crypt
echo crypt("sabzdanesh", "salt");
توابع مختلفی برای عملیات هش در PHP داریم. با مراجعه به این کامنت در مستندات میتوانید لیستی از الگوریتمهای هش و خروجی آنها را ببینید. چند مورد دیگر از معروفترین توابع عبارتاند از: sha1()
، sha256()
و password_hash()
.
پیشنهاد میکنم برای هش پسورد از password_hash()
استفاده کنید. به زودی در آموزشی جداگانه این تابع را بررسی میکنم.
افزایش امنیت هش در PHP
ما هیچ اجباری نداریم که از الگوریتمهای هش پیشفرض در PHP استفاده کنیم. بلکه میتوانیم بنا به نیازمان، الگوریتمهای جدیدی تولید کنیم. البته فرآیند تولید الگوریتم هش که ایمن و کاربردی باشد، کار زمانبر و نسبتاً دشواری است.
در مجموع، بهتر است در پروژههای غیر خاص، از الگوریتمهای پیشفرض استفاده کنیم اما به کمک ترفندها و خلاقیتهای خودمان، امنیت آن را افزایش دهیم.
مقدار salt در هش
یکی از محبوبترین و شناخته شدهترین روشها برای افزایش امنیت هش در برنامهنویسی، استفاده از salt است. در برخی منابع فارسی از معادل «نمک» برای آن استفاده میکنند که من ترجیح میدهم از همان لفظ salt استفاده کنم! 😉
سادهترین حالت استفاده از salt، چسباندن یک رشته ثابت به رشته هشنشده قبل از هش شدن است. فرض کنید میخواهیم 123
را هش کنیم. به جای اینکه این مقدار را هش کنیم، تابع هش را برای salt123
اجرا میکنیم.
هر چه salt طولانیتر و پیچیدهتر شود، مدت زمان پیدا کردن مقدار اصلی با brute force نیز افزایش پیدا میکند. همچنین وقتی هکر به رشته بدون هش برسد، چون ترکیبی از رشتهها را داریم، به سختی میتواند به مقدار اصلی برسد.
از این روش میتوان به صورت ترکیبی، چندتایی و حتی salt متغیر نسبت به زمان یا دیتاهای دیگر نیز استفاده کرد.
<?php
$password = "123";
$salt = '$Ha2%diOpsF';
echo md5($salt . "sabzdanesh");
echo "<br>";
echo crypt("text", $salt);
echo "<br>";
echo sha1("$salt$password");
مرور آموزش هش در PHP
در این آموزش بهطور خیلی خلاصه درباره عملیات hash در php صحبت کردیم. تفاوت آن با رمزنگاری را متوجه شدیم و چند تابع معروف را مرور کردیم. قطعاً توابع بیشتری داریم که بنا به نیاز (سرعت، دقت یا امکانات) میتوانیم از آنها استفاده کنیم.
با روشی ساده اما کاربردی برای افزودن «عبارت اضافی» (salt) برای افزایش امنیت آشنا شدیم. میبینید که با کمی خلاقیت، میتوانیم از چند salt استفاده کرده یا حتی از چند الگوریتم هش به طور متوالی کمک بگیریم!
شما برای چه کاری از هش PHP استفاده میکنید؟ آیا تجربه یا مشکلی در این موضوع دارید؟ یادتون باشد بخش دیدگاهها برای شما و پذیران نظرات شماست. 🙂
این آموزش برای همیشه رایگانه! میتونید با اشتراکگذاری لینک این صفحه از ما حمایت کنید یا با خرید یه فنجون نوشیدنی بهمون انرژی بدید!
میخوام یه نوشیدنی مهمونتون کنم
سپاس موفق باشید
سلام و درود
خیلی ممنون از آموزشتون
فقط اگر بخواهیم متن hash شده رو به حالت اول در بیاریم چیکار باید بکنیم؟
سلام
hash کردن یک رمزنگاری یکطرفهست؛ یعنی شما نمیتونید اون رو به متن اولیه برگردونید!
خیلی ممنونم ازتون
راهی نیست بشه پسورد هارو hash کنیم و hash بخونیم که به صورت امن باشه
چون خیلی از کلید های رمز نگاری مثل md5,base64 رو شکوندن
منظورتون از خوندن هش چیه؟
برای پسورد معمولاً از تابع
password_hash()
استفاده میکنن. همینطور bcrypt هم خوبه. البته ترکیبش با salt میتونه بهترش کنه.روند کلی هم اینطوریه که هش پسورد رو نگه میدارید. هر وقت خواستید چک کنید، چیزی که کاربر وارد کرده رو هش میکنید، اگه مشابه همون مقدار ذخیرهشده بود که درسته. چرا؟ چون hash یکتاست.
روش salt خیلی جالب بود و واقعا از آموزشتون لذت بردم
موفق باشید
سلام دمتون گرم مقاله خوب و مفیدی بود. چیز های جدیدی یاد گرفتیم 💚
درود
خوشحالیم که نکتههای جدیدی برات داشته 🙂
میگم اگر بخواهیم بگه ک هش رو ک از قبل تو متغیر
$password
بوده را echo کنه دستورش چیه ؟هر چی میزنم ارور میده
میزنم :
باز هم ارور میده
سلام
چه خطایی میده؟ echo رو بدون پرانتز انجام بدید ببینید مشکلتون برطرف میشه یا نه؟!
عالی . دمت گرم
سلام
این salt که توضیح دادید خیلی جالبه مرسی
سلام
هم جالبه هم کاربردی! خوشحالم که آموزش برات کاربردی بوده احسان عزیز.