بروزرسانی در تاریخ ۵ آذر ۱۳۹۷
امروزه باتوجه به فراگیری اینترنت و قرار گیری اطلاعات سازمان ها و شرکت های کوچک و بزرگ برروی بانک های اطلاعاتی سایت و پرتال های خود و دسترسی به اطلاعات به صورت طبقه بندی شده باتوجه به سطح و … محافظت از آنها بسیار حائز اهمیت بوده تا حدی که در سازمانهای متوسط و بزرگ بخشی به نام امنیت اطلاعات تشکیل شده است.
به دلیل محبوبیت زبان برنامه نویسی php بسیاری از سایت ها و پرتال های بزرگ و کوچک با این زبان نوشته و ایجاد شده اند و ما قصد داریم که شیوه ها و اصول و الگوریتم های رمزنگاری در php را در مقاله آموزش دهیم.
هش و رمزنگاری اطلاعات
ابتدا فرق بین هش و رمزنگاری اطلاعات را بیان میکنیم و در ادامه با آنها آشنا خواهیم شد. تفاوت اصلی بین هش و رمز نگاری این است که در هش هیچ گونه بازگشتی نداریم ولی در رمزنگاری اطلاعات بازگشت داریم.
تابع های معروف هش
تابع md5
ابتدایی ترین تابع هش میباشد. این تابع به تنهایی امن نمیباشد زیرا در این زمان بسیاری از دیتابیس های بزرگی از این هش تو اینترنت وجود دارد و بادادن هش راحت عبارت اصلی پیدا میشود. به مثال زیر توجه کنید:
1 2 3 4 5 |
$hash=md5($user); //(salt)استفاده از کلمه ی اضافی $hash=md5($user. $salt); |
اضافه کردن نمک (عبارت اضافی) به رمز عبور، طول آن را افزایش داده و باعث پیچیدگی آن میشود . بنابراین زمان مورد نیاز برای یافتن رمز با روش حمله جستجوی فراگیر، بسیار افزایش میابد و در واقع ناممکن میشود.ولی باز هم این تابع در زمان کنونی خیلی دارای ضریب امنیت بالای نمی باشد زیرا باز هم ممکن هست با دیتابیس های بزرگی که در سطح اینترنت هست رمز شما لو برود.
توجه کنید که که متغیر ها هرچیزی میتوانند باشند هش فقط نام روش است.
با اینکه به این نتیجه رسیدیم که تابع md۵ از امنیت بالایی برخوردار نمیباشد اما نگران نباشید چون php در نسخه ی ۵ به بالا از تابع های crypt
و password_hash
پشتیبانی میکند که مراتب از تابع md۵ از امنیت بیشتری برخوردارند.
تابع crypt
این تابع از تابع md۵
از امنیت بالاتری برخوردار است و خود تابع کلمه ی اضافی (salt) رندوم را اضافه میکند.توجه کنید که این تابع در نسخه های ۵ به بعد php میتوان به صورت ۲ پارامتری نوشت و salt به عنوان پارامتر دوم قرار گیرد.
1 2 3 4 5 6 7 8 9 |
// تعريف رمز عبور $password = "pasword"; // تعريف نمک $salt = "salt"; // رمزگذاري کلمه عبور با تابع $cli = crypt($password, $salt); echo $cli; |
ویا به صورت زیر که از شرط if نیز استفاده شده است.
1 2 3 4 5 6 7 8 9 10 11 |
//هش کردن $hash_pas = crypt($pas); //تشخصی پسوردی که کاربر وارد کرده است. if(hash_equals($hash_pas, crypt($pas, $hash_pas))){ echo 'password verify'; } |
دقت کنید فقط دز نسخه های php ۵ به بالا تابع crypt
میتواند دو متغیر را بپذیرد و در نسخه های پایین تر salt
را نمیتوانیم به عنوان متغیر دوم تابع در نظر بگیریم.
تابع password_hash
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//تولید هش $hash=password_hash($pas, PASSWORD_DEFAULT); //تشخیص هش if(password_verify($inputuser,$hash)){ echo 'Password is valid!'; } else { echo 'Invalid password.'; } |
کد بالا به این صورت است که ابتدا مقدار داده شده توسط تابع password_hash
هش میشود و توسط دستور شرطی if
درستی کمه ی عبور وارد شده بررسی میشود.
در تمامی موارد بالا از الگوریتم هش استفاده کرده ایم به صورتی که قابل بازگشت نیست ولی اگر اطلاعات شما نیاز به بازیابی دارند باید از قواعد رمزنگاری استفاده کنید.
هش قابل بازگشت نیست یعنی اگر اطلاعات و داده های شما نیاز به بازیابی ندارند میتوانید برای افزایش امنیت اطلاعات از هش و قواعد رمزنگاری در چهارچوب هش استفاده نمایید.
برای استفاده از الگوریتم های رمزنگاری در php میتوانید از تابع هایی ابتدایی مانند base۶۴_encode
و نیز در سطح بالاتر از تابع mcrypt_decrypt
استفاده نمایید که در ادامه توضیح خواهیم داد.
تابع base۶۴_decode
یکی از ساده ترین تابع هایی است که برای رمز نگاری استفاده میشود که با تابع base۶۴_encode
قابل بازگشت است.
1 2 3 |
str = 'This is an encoded string'; echo base64_encode($str); |
و مقدار بازگشتی آن به صورت زیر است:
1 2 3 |
$str = 'VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw=='; echo base64_decode($str); |
توجه کنید که رای کدگشایی اطلاعات(اطلاعاتی که قبلا کدگذاری شدهاند) از تابع base۶۴_decode
استفاده میکنیم.در واقع تابع بالا مقدار بازگشتی تابع base۶۴_decode
می باشد.در مقاله آموزشی الگوریتم های رمزنگاری در php ، به هیچ وجه توصیه نمی شود که از این تابع برای رمزنگاری پسوردها استفاده کنید و این قسمت طرفا یک نوع معرفی است.
تابع mcrypt_encrypt
یکی از بهترین توابع الگوریتم های رمزنگاری در php است که از الگوریتم MCRYPT_BLOWFISH
بهره می برد که یکی از بهترین الگوریتم های رمزنگاری محسوب می شود ، به این صورت که یک رشته را بر اساس کلیدی که برای آن تعریف میکنیم ، رمز و سپس توس تابع بازگشت آن یعنی mcrypt_decrypt
بازگشایی میکند.
1 2 3 4 |
$string = mcrypt_encrypt (// string $cipher,// string $key,// string $data,// string $mode,// [string $iv]); // shows the result in base64 and decrypted $base64 = base64_encode($string); $decrypted = mcrypt_decrypt($cipher, $key, $string, $mode, $iv); |
بروزرسانی :
توابع زیرمجموعه mcrypt_
در نسخه php 7.1 منسوخ اعلام شده و شما با خطای Deprecated
مواجه می شوید و در نسخه های ۷٫۱ به بعد هم این تابع کاملا حذف شده و خطای Undefined Function
نمایش داده می شود.
بنابراین توصیه می شود از این به بعد از تابع openssl_encrypt استفاده کنید.
مثال زیر نحوه استفاده از این تابع برای اینکریپت و دی-کریپت را نشان می دهد :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
function encrypt_decrypt($action, $string) { /* ================================================= * ENCRYPTION-DECRYPTION * ================================================= * ENCRYPTION: encrypt_decrypt('encrypt', $string); * DECRYPTION: encrypt_decrypt('decrypt', $string) ; */ $output = false; $encrypt_method = "AES-256-CBC"; $secret_key = 'WS-SERVICE-KEY'; $secret_iv = 'WS-SERVICE-VALUE'; // hash $key = hash('sha256', $secret_key); // iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning $iv = substr(hash('sha256', $secret_iv), 0, 16); if ($action == 'encrypt') { $output = base64_encode(openssl_encrypt($string, $encrypt_method, $key, 0, $iv)); } else { if ($action == 'decrypt') { $output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv); } } return $output; } |
نحوه استفاده از تابع :
1 2 3 4 5 6 7 8 9 10 |
<?php $plain_txt = "This is my plain text"; echo "Plain Text =" .$plain_txt. "\n"; $encrypted_txt = encrypt_decrypt('encrypt', $plain_txt); echo "Encrypted Text = " .$encrypted_txt. "\n"; $decrypted_txt = encrypt_decrypt('decrypt', $encrypted_txt); echo "Decrypted Text =" .$decrypted_txt. "\n"; if ( $plain_txt === $decrypted_txt ) echo "SUCCESS"; else echo "FAILED"; echo "\n"; |
توصیه ما این است که برای رمزنگاری در php از توایع غیرقابل برگشت مثل hash , md5 و الگوریتم های sha1 استفاده کنید تا امنیت رمزهای عبور شما حتی با لو رفتن دیتابیس به هر روشی مثل sql injection افشا و اطلاعات اکانت کاربران در اختیار افراد قرار نگیرد.
موفق و پیروز باشید.
عااالی بووود مررررسی
سلام و احترام
من در نظر دارم به شخص دیگری اجازه بدهم به سی پانل دسترسی داشته باشد ولی صرفا به دیتابیس (mysql) آن دسترسی داشته باشد و متن برنامه در دسترس وی قرار نگیرد . آیا راهکاری در این مورد دارید؟ آیا امکان دارد در سی پانل فایلهای برنامه برای یک کاربر خاص نمایش داده نشود؟ یا مثلا اینکه برای نمایش فایلهای سورس برنامه نیاز به رمز خاصی باشد؟ ممنونم ازهمکاری شما
سلام.
این رو از خود هاستینگ بپرسید که برای دسترسی دادن به فقط mysql چه کاری باید انجام بدید تا راهنماییتون کنن
سلام وقت بخیر
مقالتون عالی بود ولی میشه یکم بیشتر درباره openssl توضیح بدید. هر سایتی را که خوندم آخر نفهمیدم.
سلام. ممنون.
خوشحالیم که مفید واقع شده.
دقیقا مثل تابع mcrypt عمل میکنه و از الگوریتم رمزنگاری مشابه در بروتکل ssl استفاده میکنه و برای همین امنیت کلیدهایی که با این تابع تولید می کنید بالاست. برای همین توصیه میشه از همان مثالی که در اخر این مقاله قرار دادیم استفاده کنید و اگر میخواید درک عمیقی از عملکرد تابع داشته باشید حتما لینک تابع در سایت php.net رو به همراه کامنت هایی که براش گذاشتند رو مطالعه کنید
من متوجه کاربرد $iv نشدم
سلام
برای الگوریتم رمزنگاری AES-256-CBC باید یه کد سکرت به نام iv رو بدید
یعنی در واقع برای رمزگشایی به دو پسورد نیاز داریم؟
الگوریتم رمزنگاری AES-256-CBC ایمن هست؟
بله
بله ایمن هست
سلام مهندس شفیعی اگر هکر دو پسورد رو برگردونه وبا هم مقایسه کنه مقدار نمک رو تشخیص میده درسته ؟
و اینکه میگن password_hash باعث میشه برای یک رشته در زمان های مختلف هش های مختلف تولید بشه وقتی میخوایم پسورد رو اعتبار سنجی کنیم با تابع password_verify مشکل پیش نمیاد میشه توضیحی بفرمائید سپاس از راهنمایی تون موفق باشید
سلام. نه امنیتش بالا هست و هیچ مشکلی پیش نمیاد و همیشه هم درست تشخیص میده نگرانش نباشید
سلام
خیلی ممنونم از لطفتتون بابت این همه مقاله جذاب
در خط زیر “تابع mcrypt_encrypt” غلط املایی دارید نوشتید بهرو
سلام. خوشحالیم که مفید واقع شده. متن اصلاح شد. موفق باشید.
سلام و تشکر از آموزش های عالی تون
یه سوال ازاین میشه بجای JWT استفاده کرد برای امنیت لاگین و چک کردن؟
چون JWT رو هر چی مطلاعه کردم نتونستم سر در بیارم واقعیت آموزش ۰ تا ۱۰۰ هم چیزی پیدا نکردم
سلام. خوشحالیم که مفید واقع شده.
بله میتونید از این مورد هم استفاده کنید و مشکلی نیست.
موفق باشید.
سلام آقای شفیعی خسته نباشید
اگه بخوایم اطلاعات کاربرا به طور مثال رمز عبورشون رو هش کنم و بخوام موقع خوندن از بانک از هش دربیاد به چه شکل هست ؟؟؟
مرسی از مطالب خوبتون
سلام. ممنون خوشحالیم که مفید واقع شده.
باید از رمزنگاری های دو طرفه مثل openssl استفاده کنید تا بتونید این کار رو انجام بدید که در آخر همین پست به جای mcrypt در ورژن جدید php معرفی شده
موفق باشید.
سلام
بین اینا کدوم بهتر است:
md5
sha1
sha256
sha384
sha512
و اینکه با هم استفاده کنیم خوبه؟
مثل کد زیر:
function HashPassword( $pw ) {
for($i = 0; $i < 40000; $i++) {
$pw = md5(md5(md5(base64_encode($pw . $pw . 'veteran' . $i) . $pw . $i * 5000 . md5($i))));
}
return $pw;
}
سلام. سری sha بهتر هست و ترکیبی هم اوکی هست و مشکلی نیست میتونید استفاده کنید.
موفق باشید.
سلام . قسمتی که کد مربوط به openssl_encrypt رو به عنوان نمونه قرار دادین salt رو باید کجای کد اضافه کرد ؟
ممنون میشم یه نگاه هم به این نمونه کدی که لینکشو میزارم بکنید و بررسیش کنید
https://stackoverflow.com/a/46872528/388994
سلام. همان روشی که معرفی کردیم است و فقط یک تابع بیشتر به نام hash_hmac را استفاده کردند.
همین تابعی که قرار دادیم کار شما را راه می اندازد و نیاز به پیچیده کردن تابع نیست چرا که رشته اینکریپت شده تا حد زیادی امن است.
سلام. مقدار متغییرهای $secret_key و $secret_iv را میتونید تغییر بدید.
و بعد کافیه که به تابع نوع عملیات و رشته را پاس بدید تا نتیجه برای شما برگشت داده بشه.
موفق باشید.
واقعا ممنونم . من هر چی به وبتون سر میزنم چه از مطالب و چه به صورت پاسخ های کامنتتون بیشتر یاد میگیرم .
فقط یه سوال دیگه . الان این نوع رمز نگاری حداکثر طول رشته ای که تولید میکنه چه مقدار هست ؟
خیلی خوشحالیم که مطالب منتشر شده مفید واقع شده.
چون از الگوریتم aes استفاده میشه می توان گفت که اندازه بلاک ۱۲۸بیت و کلید هم ۱۲۸،۱۹۲،۲۵۶ میتونه باشه.
به هر حال مهم طول کاراکتر خروجی نیست و بدلیل داتشن کلید یا همان سالت به حدی امن است که به سادگی قابل کرک نیست. و بهتره برای ذخیره یا ارسال ان یکبار هم در آخر از base64 برای اینکد استفاده کنید تا کاراکترها به درستی منتقل ک خوانده بشوند.
موفق باشید.
بابت پاسخ گویی سریع سپاسگذارم 🙂
یک سوال ، بعضی جاها دیدم که میگن نیاز به $iv نیست ، و بعضی از برنامه نویس ها اون رو خالی گذاشتن ، ایا خالی گذاشتن این مورد مشکلی به وجود خواهد آورد؟
پیشاپیش بابت پاسخ تون سپاسگذارم.
الگوریتم AES نیاز به ۱۶بایت برای پر کردن بلاک ها نیاز داره برای همین از تابع فوق برای محاسبه و ساختن یک رشته رندوم ۱۶ کاراکتری برای این رمزنگاری استفاده کردیم.
لطفا داکیومنت خود php رو هم مطالعه و همچنین نتایج رو تست کنید. از iv برای دیکریپت کردن رمز استفاده کردیم و بله میتونید خالی بزارید
http://www.php.net/manual/en/function.openssl-encrypt.php
موفق باشید.
سلام آقای شفیعی
بابت زحمات ای که میکشید سپاسگذاریم.
یک سوال داشتم ، من برنامه ام از رمزنگاری aes 256 cbc برای رمزنگاری استفاده کردم (بین کلاینت و سرور) و حالا نمیدونم چطور از این روش در php استفاده کنم ، ممنون میشم پاسخ بدید.
من از ابزار : https://www.devglan.com/online-tools/aes-encryption-decryption
برای تست استفاده میکنم ، لطفا یک مثال از روش رمزنگاری AES 256 CBC ذکر کنید ، با تشکر.
سلام. خوشحالم که مطالب ارایه شده مفید واقع میشه.
با تابع openssl رمزنگاری رشته ها به الگوریتم های مختلف به سادگی هرچه تمام تر قابل انجام است .
یک مثال بسیار ساده مطابق با همین درخواست شما رو قرار می دم که به راحتی می توانید به عنوان یک تابع جمع کنید و در پروژه های مختلف استفاده کنید
در ابتدا الگوریتم رمزنگاری خود رو بصورت یک ثابت در نظر گرفتیم که در مراحل بعدی بدون qoute کردن رشته از اون استفاده کنید.
مرحله بعدی از
openssl_random_pseudo_bytes
برای ساخت یک کلید رمزنگاری ۲۵۶ بیت استفاده کردیم (در یک متغییر برای استفاده بعدی بصورت موقت ذخیره می کنیم.)بعد یک بردار اولیه برای رشته ایجاد می کنیم که آن هم برای شکستن رمز(decrypt) در آینده نیاز پیاده خواهیم کرد
بعد با تابع
openssl_encrypt()
رشته مورد نظر را با الگوریتم aes 256 cbc کد می کنیم.توجه کنید چهار مقداری که دادیم عبارتند از $data : متغییر حاوی رشته ای که قصد کد کردن آن را داریم , الگوریتم رمزنگاری , کلید رمز , ۰ هم که به معنی آپشن های پیشفرض است که می توانید
OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING
هم قرار بدید و در نهایت کلید شکستن رمز.و به اینصورت خروجی ما بصورت کد شده با الگوریتم aes 256 cbc چاپ میشه که البته ما به جای ذخیره سازی کلید بازگردانی آن را با : به این رشته متصل کردیم (برای موارد حساس این مورد توصیه نمیشه و فقط جهت نمونه تست بود وگرنه شما باید این کلید رو جایی ذخیره کنید اگر قصد بازگردانه رشته اصلی را دارید)
اگر احیانا کدهای شما اجرا نشد و با خطای call undefined function .. مواجه شدید توجه کنید که باید اکستنشن موردنظر روی سرور فعال باشه (بررسی از طریق تابع phpinfo() و فعال سازی از فایل php.ini )
;extension=php_openssl.dll
همچنین ورژن php باید بالا باشه.
موفق باشید.
ممنون از پاسخگویی . پس اگر مقدور بود یا در انتهای همین پست یا پست جدید در رابطه با openssl_encrypt هم آموزشی قرار بدین
خواهش می کنم . بله حتما این پست ویرایش و توضیحات مورد نیاز اضافه می شود.
سلام . میشه در رابطه با تابع mcrypt_encrypt توضیحات بیشتری بدین . یک مثلا عملی هم لطفا بزنید .
در قسمت کدی که برای mcrypt_encrypt قرار دادین یه سری از موارد رو کامنت کردین که مشخص نیست چی هستش.
همچنین در قسمت کد نمونه از تابع base64_encode استفاده کردین که دلیلش رو نفهمیدم .
ممنون میشم توضیح بدین
سلام. تابع mcrypt_encrypt منقضی شده و دیگر در ورژن های جدید php استفاده نمیشه و به جاش میتونید از openssl_encrypt بهره ببرید.
base64_encode هم یک تابع با قابلیت برگشتی به حالت قبل و بسیار ساده است و معمولا برای اینکه رشته های عجیب و غریب رو نبینیم از تابع بهره می بریم.
موفق باشید.
سلام من میخواستم که کاربر بعد از اینکه صفحه وب رو سیو کرد با استفاده از Ctrl + S یک محتویات بهش اضافه بهش مثلا صفحه دیگه کار نکنه و رفرش خودکار بشه!
ممنون میشم جواب رو به ایمیلم ارسال کنید
با تشکر
سلام . کد کامل در اختیار شما قرار نمیگیره و فقط نکته رو به شما میگیم و خودتون باید جستجو و درنهایت پیاده سازی کنید.
از keyCode ها در جاوااسکریپت استفاده کنید که در صورتی که کلید های ctrl یا s زده شده دستور document.body.innerHTML = “خطا خطا خطا”; را اجرا کنید تا کل محتویات صفحه پاک بشه.
موفق باشید.
سلام ممنون از مقاله هاي خوبتون،شما اول مقاله گفتيد md5 يا hash امنيت كمتري دارن!پس چرا توصيه كردين از اينا استفاده كنيم؟!
سلام . خوشحالم که مفید واقع شده . بله و فقط برای جلوگیری از لو رفتن رمزعبورهای شما حتی با هک شدن دیتابیس به روش هایی مثل sql injection توصیه شده ,حتما از رمزنگاری ها استفاده کنید. که خب فرقی نداره میتونید از روش های دیگه هم استفاده کنید و فقط مقصود این بود که توصیه کنیم که به هیچ وجه رمزعبور ها رو بصورت متن ساده (plain text) استفاده کنید. حالا فرقی ندارد از چه الگوریتمی بهره می برید در هر حال امنیت این روش ها همیشه نسبت به متن ساده بیشتر است.
موفق باشید.