简体   繁体   English

通过电子邮件获取用户并检查密码的代码有什么问题?

[英]What;s wrong with code which is getting user by email and checking for the password?

I 'm newbie to php and I 'm implementing a login system where user enters email and password and check for their existence in database (mysql in phpmyadmin) 我是php的新手,并且正在实现一个登录系统,在该系统中,用户输入电子邮件和密码,并检查其在数据库中的存在(phpmyadmin中的mysql)

the password is encrypted using this function when user first registers : 用户首次注册时,使用此功能对密码进行加密:

/**
 * 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;
}

the salt parameter which is the key to decrypt the password is stored in the database with user's info and the decrypt code is : salt参数是解密密码的密钥,它与用户信息一起存储在数据库中,解密代码为:

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

    return $hash;
}

the password is decrypted when i go and fetch the user with the email and password entered. 当我进入并使用输入的电子邮件和密码来获取用户时,密码将被解密。

/**
 * 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;
    }
}

the problem is when user enters correct email and password still this code returns NULL and i suspect something wrong with handling the password part. 问题是当用户输入正确的电子邮件和密码时,此代码仍返回NULL,我怀疑处理密码部分有问题。

Siguza's answer is correct, but your comment to his answer reflects a very reasonable confusion, because the name of the checkhashSSHA() function is a bit misleading (ie its name does not match its behaviour). Siguza的答案是正确的,但是您对他的答案的评论反映出一个非常合理的困惑,因为checkhashSSHA()函数的名称有点误导(即,其名称与其行为不匹配)。 A function name that start with "check" should be returning a boolean. 以“ check”开头的函数名称应返回布尔值。 I suggest changing it to: 我建议将其更改为:

/**
 * 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) ;
}

Now change these two lines: 现在更改这两行:

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

to this one line: 到这一行:

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

Now it's clearer and easier to use, and its behaviour matches its name. 现在,它更清晰,更易于使用,并且其行为与其名称匹配。 However, if you care to enhance the naming in your code, here are some suggestions: 但是,如果您想增强代码中的命名,请参考以下建议:

  • Change checkhashSSHA() to compareHashSSHA() . checkhashSSHA()更改为compareHashSSHA()
  • Change encrypted_password in the database to hashed_password . 更改encrypted_password在数据库中hashed_password

More importantly, the sha1 hashing algorithm is a bit old and not very secure. 更重要的是,sha1哈希算法有点陈旧,也不是很安全。 I recommend changing it to a more secure hashing like sha512. 我建议将其更改为更安全的哈希,例如sha512。 Check this and read the comment from Kai Petzke for the full story. 检查此内容,并阅读Kai Petzke的评论全文。

The problem lies in these two lines: 问题在于这两行:

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

First, you're hashing the already hashed password, instead of the plaintext password. 首先,您要哈希已哈希的密码,而不是纯文本密码。
Then you're comparing that "hash of a hash" to the plaintext password. 然后,您将“哈希的哈希”与纯文本密码进行比较。
So you're doing hash(hash(pw)) == pw , when it should be hash(pw) == hash(pw) . 所以您正在做hash(hash(pw)) == pw ,当它应该是hash(pw) == hash(pw)

You simply have to exchange $user ["encrypted_password"] and $password : 您只需要交换$user ["encrypted_password"]$password

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

I would suggest instead of using the sshhash function you look into the php function password_verify() 我建议您不要使用sshhash函数,而是查看php函数password_verify()

Check the docs on that and related functions here: http://php.net/manual/en/function.password-verify.php 在此处查看有关该功能和相关功能的文档: http : //php.net/manual/zh/function.password-verify.php

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM