我正在使用一种非常标准的cookie登录方式 – 我给用户两个cookie,一个用他的用户名,另一个用随机生成的字符串加用户特定的盐.
这是在登录时发生的事情:
$_SESSION['username']=$row[username];
$_SESSION['user_id']=$row['id'];
$loginhash=generateRandomBase64String()."_".$row['salt'];
$number_of_days = 14;
$date_of_expiry = time() + 60 * 60 * 24 * $number_of_days ;
setcookie( "userlogin", $row['username'], $date_of_expiry, "/" ) ;
setcookie( "loginhash", $loginhash, $date_of_expiry, "/" ) ;
$cryptedhash=crypt($loginhash);
$today=date("Y-m-d");
MysqL_query("update members set last_login='$today',loginhash='$cryptedhash' where id='$row[id]' ") or die(MysqL_error());
因此$loginhash值类似于Pe0vFou8qe CqhcJgFtRmoAldpuIs d_g5oijF76,并且其加密版本存储在数据库中. salt已经在数据库中,因为它是在每个用户注册时生成的.
我使用会话变量($_SESSION [用户名])来保持用户登录.然后,当用户访问网站时,我检查两件事:如果没有设置$_SESSION [用户名]但是$_COOKIE [userlogin]是,我检查哈希是否正确,以便我可以将用户登录.问题是,哈希永远不正确.
if($_COOKIE['userlogin'] && !isset($_SESSION[user_id])){
$username=MysqL_real_escape_string($_COOKIE['userlogin']);
$loginhash=MysqL_real_escape_string($_COOKIE['loginhash']);
$salt=substr($loginhash,-8);
$result=MysqL_query("select * from members where (username='$username' || email='$username') && salt='$salt' limit 1 ") or die (MysqL_error());
$row=MysqL_fetch_assoc($result);
$cryptedhash=$row['loginhash'];
if (crypt($loginhash, $cryptedhash) == $cryptedhash){
$_SESSION['username']=$row[username];
$_SESSION['user_id']=$row['id'];
}
}
$_COOKIE [userlogin]是正确的值.当我在数据库中检查用户名/ salt组合时,找到了正确的结果(echo $row [username]给出了正确的值).但是,从未满足下面的if条件.我认为我的PHP配置有些奇怪,但是我使用相同的加密机制来存储密码,并且它可以正常工作.
所以有人能看到这里出了什么问题吗?
PS我不打算在这里开始讨论cookie安全性或各种可用的散列函数. 解决方法: 这是问题所在:
在第一次调用crypt()时,您没有指定salt. 在第二次调用crypt()时,您将$cryptedhash作为salt传递.
如果您没有提供随机盐,则记录crypt()以生成随机盐,然后将该盐添加到返回的哈希中.这有副作用,如果你将返回的salt哈希作为后续调用的哈希传递,crypt()仍然会从中提取正确的salt.
不幸的是,使用的算法和salt哈希的长度/格式是基于操作系统,PHP版本以及是否指定salt参数的组合.当你以前使用过你的代码时,你很高兴在两次调用crypt()时都选择了DES.现在,您的环境使用不同的算法来对crypt()进行2次调用,因为您只在其中一个中提供了哈希.
解决方案是将一致的salt传递给对crypt()的两次调用.你可以停止将salt附加到你想要哈希的字符串,并实际将你的用户盐作为salt参数传递,一切都会好的. (编辑:北几岛)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|