【问题标题】:What;s wrong with code which is getting user by email and checking for the password?通过电子邮件获取用户并检查密码的代码有什么问题?
【发布时间】:2015-11-09 16:16:54
【问题描述】:

我是 php 的新手,我正在实现一个登录系统,用户输入电子邮件和密码并检查它们在数据库中的存在(phpmyadmin 中的 mysql)

用户首次注册时使用此功能对密码进行加密:

/**
 * Encrypting password
 *
 * @param
 *          password
 *          returns salt and encrypted password
 */
public function hashSSHA($password) {
    $salt = sha1 ( rand () );
    $salt = substr ( $salt, 0, 10 );
    $encrypted = base64_encode ( sha1 ( $password . $salt, true ) . $salt );
    $hash = array (
            "salt" => $salt,
            "encrypted" => $encrypted 
    );
    return $hash;
}

salt参数是解密密码的密钥,与用户信息一起存储在数据库中,解密代码为:

/**
 * Decrypting password
 *
 * @param
 *          salt, password
 *          returns hash string
 */
public function checkhashSSHA($salt, $password) {
    $hash = base64_encode ( sha1 ( $password . $salt, true ) . $salt );

    return $hash;
}

当我去获取输入了电子邮件和密码的用户时,密码被解密。

/**
 * Get user by email and password
 */
public function getUserByEmailAndPassword($email, $password) {
    $stmt = $this->conn->prepare ( "SELECT * FROM users WHERE email = ?" );

    $stmt->bind_param ( "s", $email );

    if ($stmt->execute ()) {
        $user = $stmt->get_result ()->fetch_assoc ();
        $stmt->close ();
        $salt = $user ["salt"];
        $hash = $this->checkhashSSHA ( $salt, $user ["encrypted_password"] );
        if ($hash == $password) {
            return $user;
        } else {
            return NULL;
        }
    } else {
        return NULL;
    }
}

问题是当用户输入正确的电子邮件和密码时,此代码仍然返回 NULL,我怀疑处理密码部分有问题。

【问题讨论】:

  • 在您的最后一个代码块中,您正在散列哈希,而不是明文密码...所以您最终将密码与哈希的哈希进行比较...
  • 请注意,您正在散列密码,不是“加密”它。

标签: php database


【解决方案1】:

Siguza 的回答是正确的,但您对他的回答的评论反映了一个非常合理的混淆,因为 checkhashSSHA() 函数的名称有点误导(即它的名称与其行为不匹配)。以“check”开头的函数名应该返回一个布尔值。我建议将其更改为:

/**
 * Decrypting password
 *
 * @param
 *          password, hash, salt
 *          returns boolean
 */
public function checkhashSSHA($password, $hash, $salt) {
    $hash2 = base64_encode ( sha1 ( $password . $salt, true ) . $salt );

    return ($hash == $hash2) ;
}

现在更改这两行:

$hash = $this->checkhashSSHA ( $salt, $user ["encrypted_password"] );
if ($hash == $password) {

到这一行:

if (checkhashSSHA($password, $user["encrypted_password"], $salt)) {

现在它更清晰、更易于使用,并且其行为与其名称相符。但是,如果您想增强代码中的命名,这里有一些建议:

  • checkhashSSHA() 更改为compareHashSSHA()
  • 将数据库中的encrypted_password更改为hashed_password

更重要的是,sha1 哈希算法有点陈旧,不是很安全。我建议将其更改为更安全的散列,如 sha512。查看 this 并阅读 Kai Petzke 的评论以了解完整的故事。

【讨论】:

    【解决方案2】:

    问题出在这两行:

    $hash = $this->checkhashSSHA ( $salt, $user ["encrypted_password"] );
    if ($hash == $password) {
    

    首先,您正在散列 已经散列的密码,而不是明文密码。
    然后,您将“散列的散列”与明文密码进行比较。
    所以你正在做hash(hash(pw)) == pw,它应该是hash(pw) == hash(pw)

    您只需交换$user ["encrypted_password"]$password

    $hash = $this->checkhashSSHA ( $salt, $password );
    if ($hash == $user ["encrypted_password"]) {
    

    【讨论】:

    • +1,但只想为 OP 添加评论。出于安全原因,不建议使用散列密码和盐返回 $user。没有其他代码需要这两个值,因此在返回 $user 之前将它们设置为 null
    • @Siguza 如果你仔细看,我不会对已经散列的内容进行散列,我正在调用 checkhashSSHA,它是一个反散列函数,它采用加密的密码,并将密码作为文本返回并放入它在 $hash 中(我的错误不应该称为 hash )然后我比较返回到用户输入的 $password 的内容
    • 是的,你不是在散列,你在调用checkhashSSHA()....但是如果你仔细观察,checkhashSSHA() 是在使用sha1() 函数进行散列。这就是西古萨的意思。这一切都是正确的,你正确地称它为哈希,但你只需要遵循这个答案并交换变量,一切都会好起来的。
    • 是的,你和@Siguza 都是对的我错过了一些东西....我的错谢谢你们的帮助
    • 不客气。这真的不是你的错。该函数的名称和行为具有误导性。有关详细信息,请参阅我的答案。
    【解决方案3】:

    我建议不要使用 sshhash 函数,而是查看 php 函数 password_verify()

    在此处查看有关该功能和相关功能的文档: http://php.net/manual/en/function.password-verify.php

    【讨论】:

    • 这并不能回答手头的问题。
    猜你喜欢
    • 1970-01-01
    • 2012-03-05
    • 2015-06-10
    • 1970-01-01
    • 2014-11-20
    • 2017-11-12
    • 2014-01-16
    • 1970-01-01
    • 2018-12-05
    相关资源
    最近更新 更多