1

Before I am crucified, I have been on this for a week and will appreciate it if anyone can help. I have also read all the articles concerning password_hash and password_verify on this platform, but none of the solutions worked for me, from string length and database length and more, so I decided to post my question.

I am writing a login script and I used password_verify; I just learned security in PHP and wanted to improve my code.

Every time I try to login, it doesn't login.

public function create() {

    // Don't forget your SQL syntax and good habits:
    // - INSERT INTO table (key, key) VALUES ('value', 'value')
    // - single-quotes around all values
    // - escape all values to prevent SQL injection
   /* $sql = "INSERT INTO users (username, password, first_name, last_name)
                      VALUES( ?, ?, ?, ?)";*/
    $sql = "INSERT INTO users (username, password, email, date_created)
                      VALUES( :username, :password, :email, :date_created)";
    try {
        // prepare sql and bind parameters
        $core = ConnectionManager::getInstance();
        $stmt = $core->con->prepare($sql);
       /*$stmt = $db->prepare("INSERT INTO users (id, username, password, first_name, last_name)
            VALUES (:id, :username, :password, :first_name, :last_name");*/
        //$stmt->bindParam(':id', 1);

        $username = $this->username;
        $password = password_hash($this->password, PASSWORD_BCRYPT);
        $email = $this->email;
        $date_created = strftime("%Y-%m-%d %H:%M:%S", time());

        /*$username = "boiy";
        $password = password_hash("redrum", PASSWORD_BCRYPT);
        $email = "bdboiy@gmail.com";
        $date_created = strftime("%Y-%m-%d %H:%M:%S", time());*/

        $stmt->bindParam(':username', $username, PDO::PARAM_STR);
        $stmt->bindParam(':password', $password, PDO::PARAM_STR);
        $stmt->bindParam(':email', $email, PDO::PARAM_STR);
        $stmt->bindParam(':date_created', $date_created, PDO::PARAM_STR);

        if($stmt->execute()) {
            $this->id = $core->con->lastInsertId();
            echo "New records created successfully";
            return true;
        } else {
            return false;
        }

    } catch (PDOException $e) {
        echo "Insert Error: " . $e->getMessage();
    }
}

That's to creat a new user. It worked.

Then I tried to login the user:

if($session->is_logged_in()) {redirect_to("admin.php");}

// Remember to give your form's submit tag a name="submit" attribute!
if (isset($_POST['submit'])) { // Form has been submitted.

    $username = trim($_POST['username']);
    $password = trim($_POST['password']);
    $YRJWA = "YRJWA";
    $string = "$2y$10$$YRJWA/EJQGkmqev6VlpteOXHwF6DeQWcU1x1uGqmOdY4CDK5.oJYi";

    // Check database to see if username/password exist.
    $found_user = User::authenticate($username, $string);


    if ($found_user) {
        //if (password_verify($password, $found_user->password)) {
            $session->login($found_user);
            log_action('Login', "{$found_user->username} logged in.");
            redirect_to("admin.php");
        //}
    } else {
        // username/password combo was not found in the database
        $message = "Username/password combination incorrect.";
    }

} else { // Form has not been submitted.
    $username = "";
    $password = "";
}

When I do this, it does not work. When I put password_verify, it does not work, so I commented it out as seen in the code above.

I then created a new page and tested my code there:

$YRJWA = "YRJWA";
$string = "$2y$10$$YRJWA/EJQGkmqev6VlpteOXHwF6DeQWcU1x1uGqmOdY4CDK5.oJYi";
//$string = 'redrum';
echo "<hr>";
$found_user = User::authenticate('boiy', $string);
print_r($found_user);
echo "<br>";
/*echo strlen($found_user->password);*/
/*echo utf8_encode($found_user->password);
echo utf8_decode($found_user->password);*/
echo "<br/>";
//echo substr($found_user->password, 0, 60);
var_dump($found_user->password);

echo "<br>";
if(password_verify('redrum', $found_user->password)) {
    echo "Valid";
} else {
    echo "Invalid";
}
ConnectionManager::close();

When I use the password directly from database, it returns the right data and prints "Valid".

When I remove the comment and try "redum" it gives this error

Notice: Trying to get property of non-object in C:\xampp\htdocs\WealthPlus\private\index.php on line 36 NULL

Notice: Trying to get property of non-object in C:\xampp\htdocs\WealthPlus\private\index.php on line 39 Invalid

public static function authenticate($username="", $password="") {
    $sql  = "SELECT username, password FROM users WHERE username = :username AND password = :password LIMIT 1";
    try {

            $core = ConnectionManager::getInstance();
            $stmt = $core->con->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
            $stmt->execute([':username' => $username, ':password' => $password]);
            $stmt->setFetchMode(PDO::FETCH_CLASS, "User");
            $users = $stmt->fetch();
        //if (password_verify($password, $users->password)) {
            return $users;
        //}
    //return !empty($users) ? array_shift($users) : false;
    }catch (PDOException $e) {
        echo "Error: " . $e->getMessage();
    }
}
A J
  • 3,970
  • 14
  • 38
  • 53
Boiy
  • 19
  • 7
  • i will post images if needed.. i have been on this for a week and its lowing down what am developing... PLS HELP – Boiy Sep 28 '16 at 00:10
  • When i use the string from database directly.. it works... but when i revert back to my password "redrum" and use the password_verify function on it.. it does not work – Boiy Sep 28 '16 at 00:12
  • 1
    You are using a framework right? Which one are you using? – RiggsFolly Sep 28 '16 at 00:14
  • No am not using any framework, i am using object oriented programming .. wrote the codes and hoping to upgrade it to a framework later in future, and i am using PHP 7 – Boiy Sep 28 '16 at 00:17
  • It would also help if you pointed out line 36 and 39 in one of these bits of code so we were not having to guess where the error is coming from – RiggsFolly Sep 28 '16 at 00:18
  • Then maybe you should show us what `User::authenticate()` does. – RiggsFolly Sep 28 '16 at 00:20
  • oh ok, Line 36: var_dump($found_user->password); and Line 39:if(password_verify('redrum', $found_user->password)){ echo "Valid"; }else{ echo "Invalid"; } – Boiy Sep 28 '16 at 00:21
  • One obvious mistake is you should be fetching the user details using ONLY the `username` and not the password as weel. Because at that stage you dont know what the password actually is on the database. – RiggsFolly Sep 28 '16 at 00:22
  • `var_dump($found_user->password)` gives a message that say `Trying to get property of non-object` and in a week you cannot work out that this line `User::authenticate($username, $string);` has obviously failed and not returned an object. Maybe you should look for another hobbie my friend – RiggsFolly Sep 28 '16 at 00:24
  • @RiggsFolly.. give me a min.. the code can fit into the comment block...let me try Answer your question – Boiy Sep 28 '16 at 00:25
  • [edit] your question and show `authenticate` – Drew Sep 28 '16 at 00:26
  • if your `select` stmt has the password in the `where` clause, you screwed up – Drew Sep 28 '16 at 00:27
  • I know it has failed...I know it has not returned an object,.., i tried other stuffs, even changed my Fetch Mode.. there is a possibility i am missing something someone else would see.. if you see it.. it would be great to point it out – Boiy Sep 28 '16 at 00:27
  • 1
    See my PDO example [here](http://stackoverflow.com/a/32556010) . See how it does verify – Drew Sep 28 '16 at 00:30
  • **WARNING**: Writing your own access control layer is not easy and there are many opportunities to get it severely wrong. Please, do not write your own authentication system when any modern [development framework](http://codegeekz.com/best-php-frameworks-for-developers/) like [Laravel](http://laravel.com/) comes with a robust [authentication system](https://laravel.com/docs/5.2/authentication) built-in. – tadman Sep 28 '16 at 02:05

1 Answers1

1

If you're saving a hashed password you cannot look it up by password. What you need to do is fetch the user record, then verify the password using password_verify.

You even have code like that in there that's disabled:

public static function authenticate($username, $password) {
    try {
        $core = ConnectionManager::getInstance();
        $stmt = $core->con->prepare("SELECT password FROM users WHERE username = :username";, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
        $stmt->execute([ ':username' => $username ]);
        $stmt->setFetchMode(PDO::FETCH_CLASS, "User");

        $user = $stmt->fetch();

        if (password_verify($password, $user['password'])) {
            return $users;
        }
    } catch (PDOException $e) {
        echo "Error: " . $e->getMessage();

        return false;
    }
}

Remember, add a UNIQUE constraint on things like username and you won't need to worry about LIMIT 1 as it will be impossible to get two rows.

tadman
  • 208,517
  • 23
  • 234
  • 262