آموزش هش کردن در زبان PHP

به کمک هش‌ها می‌توانیم داده‌های مهم را کد کنیم. 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");
مثال: خروجی هش md5 در PHP
مثال: خروجی هش md5 در PHP

همانطور که در تصویر بالا می‌بینید، هش «سبز دانش» یک رشته نامفهوم و طولانی‌تر از رشته اصلی است. خروجی این الگوریتم همیشه یک رشته متنی 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

افزایش امنیت هش در 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 استفاده می‌کنید؟ آیا تجربه یا مشکلی در این موضوع دارید؟ یادتون باشد بخش دیدگاه‌ها برای شما و پذیران نظرات شماست. 🙂