php 字符串hash比较,关于php:Crypt函数在比较字符串到hash时不起作用

我使用的是一种非常标准的cookie登录方式——我给用户两个cookie,一个使用用户名,另一个使用随机生成的字符串和用户特定的salt。

登录时会发生以下情况:

$_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[username]来保持用户登录。然后,当用户访问站点时,我检查两件事情:如果没有设置$_SESSION[username],但$_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($loginhash, $cryptedhash)和$cryptedhash返回的值。数据库字段是否太短,无法容纳整个哈希值?

db字段是varchar(64),非常长。如果我手动从cookie中提取字符串并执行crypt("stringhere", $cryptedhash),它仍然不起作用。crypt($loginhash, $cryptedhash)返回格式正确的散列,在本例中,$1$8CwqG9Pq$Y.3YmFOhXc78ucBki4GPA.返回格式正确的散列。

我可能是错的,但这一行是否会说,如果(crypt(hash,salt)=salt…加盐不会使结果不等于盐吗?

@contextswitch php.net/manual/en/function.crypt.php这些php文档说,您可以使用该方法来验证哈希值

是否使用转义字符串修改哈希的输入,使crypt认为字符串不同?尝试在未转义的字符串上使用crypt。这里还插入有关mysql_php函数的警告。

在上面的代码中,您有:!isset($_SESSION[user_id]),应该是!isset($_SESSION['user_id'])。

你能在$row=mysql_fetch_assoc($result);之后给我们看一下print_r($row);吗?我认为你用盐不正确

@本尼希尔,我向你保证,这与此事无关。

河豚使这一切更容易(仅供参考)。您只需在注册时将预构建函数调用为salt,然后在登录时检查函数。

问题是:

在对crypt()的第一个调用中,不指定salt。在对crypt()的第二个调用中,您将$cryptedHash作为salt传递。

如果不提供随机salt,则记录crypt()以生成随机salt,然后将该salt预先发送到返回的哈希。这样做的副作用是,如果将返回的salt+哈希作为后续调用的哈希传递,crypt()仍将从中提取正确的salt。

不幸的是,使用的算法和salt+哈希的长度/格式是基于操作系统、PHP版本以及是否指定salt参数的组合。当您以前使用代码时,您遇到了一个愉快的意外,即在对crypt()的两个调用中都选择了des。现在,您的环境对crypt()的两个调用使用了不同的算法,因为您只在其中一个调用中提供了散列。

解决方案是向crypt()的两个调用传递一致的salt。您可以停止将salt附加到要散列的字符串中,并实际将用户salt作为salt参数传递,一切都会好起来的。

如果您使用的是5.5.0或更高版本的PHP,那么您应该看看phpDoc-密码哈希!我知道你说过你不想讨论不同的散列函数,但我认为这一个让你更容易,因为它应该摆脱你的问题,而且(在我看来)更容易使用!

下面是您的新函数代码:(未测试,如果中断请评论)

$_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=password_hash($loginhash, PASSWORD_DEFAULT, array("cost" => 10));

// a cost of 10 is standard, you may want to adjust it according to your hardware (lower/higher cost means faster/slower)

$today=date("Y-m-d");

mysql_query("update members set last_login='$today',loginhash='$cryptedhash' where id='$row[id]'") or die(mysql_error());

使用PASSWORD_DEFAULT将使舒尔即使在未来的版本中也始终使用最强大的算法。

if($_COOKIE['userlogin'] && !isset($_SESSION[user_id])){

$username=mysql_real_escape_string($_COOKIE['userlogin']);

$loginhash=$_COOKIE['loginhash']; // i guess you should not use mysql_real_escape_string

$salt=mysql_real_escape_string(substr($loginhash,-8)); // here would be the place to use it

$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 (password_verify($loginhash, $cryptedhash)){

$_SESSION['username']=$row[username];

$_SESSION['user_id']=$row['id'];

}

}

此行错误$loginhash=mysql_real_escape_string($_COOKIE['loginhash']);您不需要转义它(您不在数据库中使用它),在传递给crypt()时必须使用它而不改变,这样该行就可以写为$loginhash=$_COOKIE['loginhash'];(至少对于这部分代码而言)。

盐已经被修复了,它存储在数据库中,对每个用户都是唯一的,并且是不可更改的。

哦,我看你自从我发表评论后就改变了答案。但它并不能解决这个问题——如果我不转义字符串,它就保持不变;如果我直接在crypt函数中使用字符串而不是$loginhash,它就保持不变(手动复制/粘贴)。

你能在$row=mysql_fetch_assoc($result);后给我看一下print_r($row);吗?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值