PDA

View Full Version : سوال: مشکل در ساخت پسورد قوی



مهرداد سیف زاده
سه شنبه 10 بهمن 1391, 09:17 صبح
با راهنمایی که در سایتهای phpmaster (http://phpmaster.com/password-hashing-in-php/).com+parnet.ir (http://aparnet.ir/206-%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D9%87%D8%B4hash-%DA%A9%D8%B1%D8%AF%D9%86-%D9%BE%D8%B3%D9%88%D8%B1%D8%AF-%D8%AF%D8%B1-php) میخوام پسورد قوی برای فرم ثبت نام و ورود خروج کاربران درست کنم. در مراحل ساخت و قبل از ذخیره در دیتابیس تست کردم درست کار میکنه ولی بعد از ذخیره در دیتا بیس پسورد رو نمیشناسه و شرط رو غلط بر می گردونه.
کدهای من بصورت زیر هستن:



<?php
require_once("include/database.php");// database class

// recive the user & pass from user
$user = $_POST['username'];
$pass = $_POST['pass'];

// function generate password width hash
function generateHash($pass) {
if (defined("CRYPT_BLOWFISH") && CRYPT_BLOWFISH) {
$salt = '$2y$11$' . substr(md5(uniqid(rand(), true)), 0, 22);
return crypt($pass, $salt);
}
}

// verify the create password and test ofter save the databse
function verify($password, $hashedPassword) {
return crypt($password, $hashedPassword) == $hashedPassword;
}

$password = generateHash($pass);
if (verify($pass, $password)) {
echo "yes";
} else {
echo "no";
} //the yes print

//database saved
$sql = "INSERT INTO users (user_name,password) VALUE (\"{$user}\",\"{$password}\")";
$database->query($sql);
?>

و همچنین کد شناسایی کاربر :


<?php
require_once("include/database.php");

function verify($pass, $pass_login) {
return crypt($pass, $pass_login) == $pass_login;
}
$user = $_POST['username_login'];
$pass = $_POST['pass_login'];

$sql = "SELECT * FROM users WHERE user_name=\"{$user}\"";
$user_recive = $database->query($sql);
$find_user = $database->fetch_array($user_recive);

$pass_login = $find_user['password'];

if (verify($pass, $pass_login)) {
echo "yes";
} else {
echo "no";
}

?>



اینکدینگ دیتابیس رو روی utf8-bin گذاشتم و فایل php هم بصورت utf-8 بدون bom ذخیره کردم.
البته در مرحله فراخوانی پسورد از تابع زیر برای تبدیل به رشته استفاده میکنم ارور میده:


$pass_login = string($find_user['password']);


ممنون میشم دوستان راهنمایی کنید.

siavashsay
سه شنبه 10 بهمن 1391, 11:21 صبح
دوست عزیز !
شما درست عمل میکنید اما تنها تا موقعی که دارید رمز رو درست میکنید !
در تابع شما رمز ورودی کاربر با یک مقدار متغیر که بهش SALT میگن داره ادغام میشه و بعد Hash شده و بعد مقدار رو به شما میده و شما هم در دیتابیس ذخیره میکنید !
اما توجه کنید که شما باید اون مقدار SALT که توسط سیستم به صورت رندم داره تولید میشه ( در این خط ) :

$salt = '$2y$11$' . substr(md5(uniqid(rand(), true)), 0, 22);
رو هم همونجا همراه رمز کاربر در یک فیلد دیگه توی دیتابیس باید ذخیره کنید !
مثلا باید علاوه بر فیلدهای username - password یک فیلد دیگه هم توی دیتابیس داشته باشید به نام salt و اون مقدار رندم رو در زمان ذخیره اطلاعات در دیتابیس هم ذخیره کنید !
و در موقع فراخوانی باید رمز ورودی کاربر رو از POST گرفته - مقدار SALT رو از دیتابیس گرفته بعد توسط همون تابع دوباره هش کنید و همون روند رو اجرا کنید !
در کل منظور این هست که مقدار سالت رو در همون موقع ثبت رمز و نام کاربری کاربر در دیتابیس ذخیره کرده و بعد موقع فراخوانی اون رو با رمز ادغام - هش و مقایسه کنید !
موفق باشید

Mohsen.
سه شنبه 10 بهمن 1391, 11:32 صبح
فکر نکنم لازم باشه مقدار salt ذخیره بشه. وقتی با crypt انجام میشه لازم نیست ذخیره بشه.

siavashsay
سه شنبه 10 بهمن 1391, 11:59 صبح
فکر نکنم لازم باشه مقدار salt ذخیره بشه
میشه توضیح بدید ؟!
اگر نیازی نباشه که SALT ذخیره بشه پس دیگه چه نیازی به SALT هست ؟!
SALT رشته ای هست که به صورت رندم داره تولید میشه !
در این کد :

$salt = '$2y$11$' . substr(md5(uniqid(rand(), true)), 0, 22);
و اگر ثبت نشه سیستم چطوری میخواد مقدار اون رو بدست بیاره و بعد مقایسه کنه با ورودی اون کاربر خاص ؟!
اگر مقدار SALT یه رشته ثابت و همیشگی بود خوب یه چیزی ! ( که البته در اون صورت هم همچین کاربرد خاصی نداشت ) ! در کل مزیت SALT به رندم بودن اون هست و انگار برای رمز هر کاربر دارید یک unique id خاص تولید میکنید !
حالا به خاطر همین موضوع شما باید رشته SALT رو برای هر کاربر به صورت جدا ذخیره سازی کنید !
در غیر اینصورت SALT کاربرد خاصی نداره !

Mohsen.
سه شنبه 10 بهمن 1391, 12:03 عصر
خب شما ضمیمه رو دانلود کردین؟

Mohsen.
سه شنبه 10 بهمن 1391, 12:05 عصر
من الان بدون ذخیره مقدار Salt درستی و اشتباه بودن پسورد کاربر رو میتونم تشخیص بدم. داخل ضمیمه گذاشتم.


Also, if you use Bcrypt then there is no need to store your salts in the database.

siavashsay
سه شنبه 10 بهمن 1391, 12:19 عصر
میشه بگید تابع crypt چطور اینکارو میکنه ؟!
سیستم تشخیص اون چطور هست ؟!

Mohsen.
سه شنبه 10 بهمن 1391, 12:20 عصر
دیگه اینو نمیدونم :لبخند:
اما میدونم که بالاترین امنیت رو داره. چون مقدار Salt ذخیره نمیشه.

siavashsay
سه شنبه 10 بهمن 1391, 12:27 عصر
مقدار SALT هم در دیتابیس ذخیره میشه !
فقط بحثی که هست !
من الان یک رشته ثابت رو به cryptدادم و هر دفعه یک رشته بهم میده ! خوب اینش جالبه !
یعنی چطوریه ؟!

mamali-mohammad
سه شنبه 10 بهمن 1391, 13:49 عصر
خب هر دفعه یه رشته بده چه سودی داره ؟!
در هر صورت در دیتابیس ذخیره میشه و کسی هک کنه میتونه برش داره
مهم اینه اگه برش داشت نتونه استفاده کنه
به نظرم هنگام ورود با یه رشته جمع بشه در کدهای php دیگه قابل هک نیست

مهرداد سیف زاده
سه شنبه 10 بهمن 1391, 13:57 عصر
آموزش انگلیسی گفته بود مقدار salt دیگه لازم نیست ذخیره بشه. اگر هم ذخیره کنی چون کلید برای ساخت هست و در هنگام بازگردانی به کمک تابع crypt رمز ورودی به رمز واقعی بر گردونده میشه. منم قبل از ذخیره در دیتابیس رمز ساخته شده رو با رمز ورودی کاربر مقایسه کردم دیدم salt نمیخواد. ولی مشکلم در کار با پایگاه داده هست انگار در هنگام ذخیره از نظر کاراکتری مشکلی پیش میاد که بعد از برداشت رمز عبور از پایگاه داده مقدار نا معتبر بر میگردونه.
خط ۲۲ تا ۲۶ کد اول این تست رو انجام میده. یعنی ابتدا رمز ورودی رو از post می گیره، با تابع hash به صورت رمز در میاره، و بعد رمز ساخته شده را با رمز وارد کرده اول verify کردم دیدم yes بر می گیردونه ولی بعد از ذخیره در دیتا بیس no بر می گردونه.
ممنون میشم اگر به مقاله انگلیسی هم نگاهی بندازید شاید بعضی نکات رو گفته من خوب ننوشتمش.

siavashsay
سه شنبه 10 بهمن 1391, 14:01 عصر
مهرداد جان !
شاید نوع type فیلد password رو توی دیتابیس VARCHAR انتخاب نکردی ! و یا تعداد کاراکترها رو کم انتخاب کردی !
مثلا توی دیتابیس مقدار کاراکتر رو 20 تا انتخاب کردی اما این تابع دار 60 تا (مثلا ) کاراکتر برمیگردونه !
شما نوع تایپ رو VARCHAR و تعداد کاراکتر رو 100 تا کن ببین درست میشه ؟!
--
ضمنا کلا یوزرهاتو پاک کن و مجدد یوزر بساز ! چون اطلاعات قبلی با اطلاعات جدید فرق میکنن !

مهرداد سیف زاده
سه شنبه 10 بهمن 1391, 14:12 عصر
ممنون من مقدار روی ۴۰گذاشته بودم که با تغییر به ۲۰۰ راه افتاد.
اسکریپت خیلی خوبی هست توی وب گشتم دیدم بهترین و سبکترینش همین بود. اگه شما از چیزهای دیگه ای استفاده می کنید ممنون میشم معرفی کنید.

siavashsay
سه شنبه 10 بهمن 1391, 14:18 عصر
خواهش میکنم !
ممنونم به هرحال ! ما هم از همین باید استفاده کنیم دیگه :)

زینب فاطمی
چهارشنبه 26 آذر 1393, 15:10 عصر
فکر نکنم لازم باشه مقدار salt ذخیره بشه. وقتی با crypt انجام میشه لازم نیست ذخیره بشه.
سلام
ممنون از فایلی که گذاشتید .
من با یه مشکلی مواجه شدم . وقتی نام کاربری رو فارسی مینویسم توی دیتابیس اینچوری نمایش میده : زی&#16
و موقع لاگین پیام نادرست بودن رو میده ولی وقتی انگلیسی میزنم کد درست هست . توی دیتابیس collation رو utf8_persian_ci گذاشتم ولی فارسی رو درست ذخیره نمیکنه میده چرا؟

phpdev
چهارشنبه 26 آذر 1393, 15:22 عصر
بعد از اتصال به دیتابیس و قبل از هر کوئری اینو بزن


mysql_query("set names 'utf8'");
فکر کنم با PDO هم همین باشه و اگر mysqli هستش این

mysqli_set_charset ('utf8')

زینب فاطمی
چهارشنبه 26 آذر 1393, 15:38 عصر
ممنون ولی درست نشد . توی اتصال utf8 در نظر گرفته شده

$db = new PDO('mysql:host=localhost;dbname=test;charset=UTF8 ', 'root', '');

phpdev
چهارشنبه 26 آذر 1393, 17:19 عصر
انکودینگ صفحه چی هست؟ اینجوری هست یا نه ؟

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

کوئری با دیتابیس رو قبل از این خط میزنی یا بعدش؟

زینب فاطمی
چهارشنبه 26 آذر 1393, 17:28 عصر
ممنون خوب شد یاداوری کردید . من تو کدهای خودم میذارم ولی اینجا چون اون فایل رو تست میکردم توش نبود .من توجه نکردم . ممنونم .