0

I have a login code I want to use a password hash on, but when I tried to login, the progress bar will roll for eternity without logging in. below are my password hash creation, and login code. Anyone with solution on how i can resolve the issue is highly welcome.

hash creation code

    if(empty($_POST['password']))
            unset($_POST['password']);
        else
        $_POST['password'] = password_hash($_POST['password'], PASSWORD_DEFAULT);
        extract($_POST);
        $data = '';
        foreach($_POST as $k => $v){
            if(!in_array($k,array('id'))){
                if(!empty($data)) $data .=" , ";
                $data .= " {$k} = '{$v}' ";
            }
        }
        if(empty($id)){
            $qry = $this->conn->query("INSERT INTO users set {$data}");
            if($qry){
                $id=$this->conn->insert_id;
                $this->settings->set_flashdata('success','User Details successfully saved.');
                foreach($_POST as $k => $v){
                    if($k != 'id'){
                        if(!empty($data)) $data .=" , ";
                        if($this->settings->userdata('id') == $id)
                        $this->settings->set_userdata($k,$v);
                    }
                }

Login code

    public function login(){
        
        extract($_POST);

        $stmt = $this->conn->prepare("SELECT * from users where username = ? and password = ? ");
        $password = password_verify($password, $hashed_password); 
        $stmt->bind_param('ss',$username,$password);
        $stmt->execute();
        $result = $stmt->get_result();
        if($result->num_rows > 0){
            foreach($result->fetch_array() as $k => $v){
                if(!is_numeric($k) && $k != 'password'){
                    $this->settings->set_userdata($k,$v);
                }

            }
            $this->settings->set_userdata('login_type',1);
        return json_encode(array('status'=>'success'));
        }else{
        return json_encode(array('status'=>'incorrect','last_qry'=>"SELECT * from users where username = '$username' and password = md5('$password') "));
        }
    }
    public function logout(){
        if($this->settings->sess_des()){
            redirect('admin/login.php');
        }
    }
  • 1
    Question : How to you "generate / retrieve" $hashed_password ? (the line $password = password_verify($password, $hashed_password);) – Ken Lee Jun 25 '23 at 03:15
  • 3
    I don't know how you _think_ `password_verify()` works, but you get the hash from the DB _first_, and then use `password_verify()` to check if the plaintext matches the hash. You workflow looks like you just shoved a new workflow over an old on without consideration. – Sammitch Jun 25 '23 at 03:49
  • 3
    Do not use extract() on untrusted data, like user input. – James Jun 25 '23 at 04:18
  • 1
    Does this answer your question? [How to use PHP's password\_hash to hash and verify passwords](https://stackoverflow.com/questions/30279321/how-to-use-phps-password-hash-to-hash-and-verify-passwords) – Progman Jun 25 '23 at 11:43

1 Answers1

1

To be honest, I faced some difficulties in reading and comprehending your code. I attempted to rectify some noticeable errors. I recommend starting by cleaning up your code and adding comments to explain the logic behind certain sections.

Below is the modified code with comments clarifying the errors:

Code for Hash Creation:

Hash creation

if(empty($_POST['password'])) {
    unset($_POST['password']);
} else {
    $_POST['password'] = password_hash($_POST['password'], PASSWORD_DEFAULT);
}

extract($_POST);

$data = '';
foreach($_POST as $k => $v){
    if(!in_array($k, array('id'))){
        if(!empty($data)) {
            $data .= " , ";
        }
        $data .= " {$k} = '{$v}' ";
    }
}

if(empty($id)){
    $qry = $this->conn->query("INSERT INTO users SET {$data}");
    if($qry){
        $id = $this->conn->insert_id;
        $this->settings->set_flashdata('success','User Details successfully saved.');
        foreach($_POST as $k => $v){
            if($k != 'id'){
                if(!empty($data)) {
                    $data .= " , ";
                }
                if($this->settings->userdata('id') == $id) {
                    $this->settings->set_userdata($k, $v);
                }
            }
        }
    }
}

Explanation of errors and fixes:

  1. Missing curly braces (Really not needed with PHP 8+):

    • Issue: The if statement was missing curly braces, which could lead to incorrect code interpretation and execution.
    • Fix: Added curly braces for proper code block execution.
  2. Missing space in SQL query:

    • Issue: The SQL query in the INSERT INTO statement was missing a space before the SET keyword, resulting in a syntax error.
    • Fix: Added a space before SET in the SQL query.
  3. Redundant check for empty $data:

    • Issue: The loop inside the if($qry) block was checking for !empty($data) unnecessarily.
    • Fix: Removed the redundant check for !empty($data) inside the loop.

It's important to consider security measures, such as input validation and prepared statements, to protect against SQL injection attacks.

Login code

public function login() {
    extract($_POST);

    $stmt = $this->conn->prepare("SELECT * from users where username = ?"); // Removed 'password' from the query
    $stmt->bind_param('s', $username);
    $stmt->execute();
    $result = $stmt->get_result();
    if ($result->num_rows > 0) {
        $row = $result->fetch_assoc();
        if (password_verify($password, $row['password'])) { // Verify the password against the hashed password in the database
            foreach ($row as $k => $v) {
                if (!is_numeric($k) && $k != 'password') {
                    $this->settings->set_userdata($k, $v);
                }
            }
            $this->settings->set_userdata('login_type', 1);
            return json_encode(array('status' => 'success'));
        } else {
            return json_encode(array('status' => 'incorrect', 'last_qry' => "SELECT * from users where username = '$username'")); // Removed password from the last_qry
        }
    } else {
        return json_encode(array('status' => 'incorrect', 'last_qry' => "SELECT * from users where username = '$username'"));
    }
}

public function logout() {
    if ($this->settings->sess_des()) {
        redirect('admin/login.php');
    }
}

Explanation of the error and fixes:

  1. Incorrect usage of password_verify():

    • Issue: The variable $hashed_password was not defined in the code, and password_verify() requires the hashed password stored in the database as the second parameter.
    • Fix: Removed the usage of $hashed_password and updated the code to verify the entered password with the hashed password stored in the database.
  2. Accessing result rows incorrectly:

    • Issue: The loop foreach ($result->fetch_array() as $k => $v) was incorrectly fetching the row as both an associative and numeric array.
    • Fix: Updated the code to use $result->fetch_assoc() instead, which fetches the row as an associative array.
  3. Redundant password comparison:

    • Issue: The password was compared twice, once with password_verify() and again in the last query string for the incorrect status response.
    • Fix: Removed the password comparison from the last query string since it's unnecessary.

The fixed code assumes that the password column in the users table stores hashed passwords using password_hash().

Samuel
  • 182
  • 9