HiveBrain v1.2.0
Get Started
← Back to all entries
patternphpMinor

Authentication using PDO

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
usingauthenticationpdo

Problem

I'm new to PDO, so I was wondering if you guys could check over my PDO code for efficiency (and if the PHP can be improved)

public function ValidateUser($username = '', $password = '')
{
    $prefix = "SELECT ";
    $type = 'COUNT(id)';
    $suffix = " FROM users WHERE username = :username LIMIT 1";
    if($grabUser = $this->db->prepare($prefix.$type.$suffix))
    { 
        $grabUser->bindParam(":username", $username, PDO::PARAM_STR);
        $grabUser->execute();
        if(count($grabUser->fetchColumn()) db->prepare($prefix.$type.$suffix))
    { 
        $grabUser->bindParam(":username", $username, PDO::PARAM_STR);
        $grabUser->execute();
        $salt = $grabUser->fetch()['salt'];
        $password = $this->core->blueHash($password, $salt);
    }
    else {
        return array(0,0);
    }

    $stmt = "SELECT COUNT(id) FROM users WHERE username = :username AND password = :password LIMIT 1";
    if($checkFinal = $this->db->prepare($stmt))
    { 
        $checkFinal->bindParam(":username", $username, PDO::PARAM_STR);
        $checkFinal->bindParam(":password", $password, PDO::PARAM_STR);
        $checkFinal->execute();
        if(!count($checkFinal->fetchColumn()) > 0)
        {
            return array(0,0);
        }
        return array(count($checkFinal->fetchColumn()),$password);
    }
    return array(0,0);
}


This code checks that the supplied username and password are correct and if so, an array is returned.

EDIT: AJAX file where ValidateUser() is used:

```
ajaxCheck();

header("Content-Type: application/json");
$json = array();

if(USER_ID input($_POST['name']);
$password = $core->input($_POST['pword']);

$valid = $users->ValidateUser($username, $password);
if($valid[0] == 0)
{
$json[0] = "error";
$json[1] = "ajax";
$json[2] = "These details are incorrect.";
}
elseif($valid[0] > 0)
{
$_SESSION['login']['username'] = $users->GrabUserVar($users->Name2id($username),"username");

Solution

Efficiency

You currently perform three queries:

  • check if a user with that name exists



  • get salt for that username



  • check if user with that username and password exist



You can perform all these actions with one query:

SELECT salt, password FROM users WHERE username = :username LIMIT 1;


Then just hash the supplied password with the salt from the db, and compare the result to the password from the db. It might look something like this:

if (hash_equals($grabUser->fetch()['password'], $this->core->blueHash($password, $grabUser->fetch()['salt'])) {
    echo 'valid password';
}


Return Early

If you negate your if clauses, you can safe one level of nesting, which I think results in more readable code, because nesting decreases readability, and because it's clearer to what if clause the else clause belongs. Eg:

if(!($grabUser = $this->db->prepare($prefix.$type.$suffix))) 
{
    return array(0,0);
}

$grabUser->bindParam(":username", $username, PDO::PARAM_STR);
$grabUser->execute();
if(count($grabUser->fetchColumn()) <= 0)
{
    return array(0,0);
}


Misc

  • it's unclear why you are returning an array. It seems to always contain [1, $userPassword]. Why do you need to return the password? And wouldn't it be easier to just return true or false instead of 1 or 0 inside an array? At least I would add a PHPDoc style comment explaining what is returned.



  • I would extract some of the code to its own function to increase readability and avoid duplication. eg you could have fetchFromUser($columnName, $username).



  • I don't know what password hashing you currently use, but I would think about switching to bcrypt. It's easier to use (you don't have to manage salts, etc), and is currently considered secure.

Code Snippets

SELECT salt, password FROM users WHERE username = :username LIMIT 1;
if (hash_equals($grabUser->fetch()['password'], $this->core->blueHash($password, $grabUser->fetch()['salt'])) {
    echo 'valid password';
}
if(!($grabUser = $this->db->prepare($prefix.$type.$suffix))) 
{
    return array(0,0);
}

$grabUser->bindParam(":username", $username, PDO::PARAM_STR);
$grabUser->execute();
if(count($grabUser->fetchColumn()) <= 0)
{
    return array(0,0);
}

Context

StackExchange Code Review Q#87932, answer score: 2

Revisions (0)

No revisions yet.