1

I have some code here for a login system, that is purely or learning purposes, created with some major help from the great people of stackoverflow, and i was told not to store the salt and the hash seperate, but rather, together. I am wondering how I am going to compare the passwords when the user tries to login. if the salt is not stored, how can i compare the two. Can anyone help?

require("constants.php");
$DBH = new mysqli($dbhost, $dbuser, $dbpass, $dbname);

function createSalt() {
    $length = mt_rand(64, 128);
    $salt = '';
    for ($i = 0; $i < $length; $i++) {
        $salt .= chr(mt_rand(33, 255));
    }
    return $salt;
}
//Salt function created by ircmaxell

function registerNewUser() {
    //Check to see if     Username Is In Use//
    $q = $DBH->prepare("SELECT id FROM users WHERE username = ?"); 
    $username = filter_var($username, FILTER_SANITIZE_STRING);
    $data = array($username);
    $q->execute($data);
    $row = $q->fetch();

    if ($row === false) { 
        //If Username Is Not Already In Use Insert Data//
        $hash = hash('sha256', $pass);
        $salt = createSalt();
        $hash = hash('sha256', $salt . $hash . $pass);  //UPDATED
        $data = array($username, $hash, $salt);
        $qInsert = $DBH->prepare(
            "INSERT INTO users (username, password, salt) values (?, ?, ?)"
        );
        $qInsert->execute($data); //Inserts User Data Into Table//  
    }
}
mcbeav
  • 11,893
  • 19
  • 54
  • 84

3 Answers3

2

You have to query your database to retrieve the user row (if any), get the salt and use the same algorithm over the password provided by the user. If both hashes matches the user provided a good password.

doing some code it would make something like this:

$qSelect = $DBH->prepare('SELECT salt,password FROM users WHERE username = ?');
$qSelect->execute();
$qSelect->bind_result($salt, $db_password);
$qSelect->fetch();

if($salt == null){
  // username doesn't exist
  return;
}    

$hash = hash('sha256', $pass);
$hash = hash('sha256', $salt . $hash . $pass);  
if($hash == $db_password){
   // login ok
} else {
   // login nok
}
RageZ
  • 26,800
  • 12
  • 67
  • 76
  • Would i have to store the salt somewhere? Because running the code for the salt again will not produce the same results, so I can't think of another way to recreate the hash. – mcbeav Dec 16 '10 at 03:49
  • @mcbeav: the same salt and the same password should **always** produce the same hash. – zerkms Dec 16 '10 at 03:49
  • "Would i have to store the salt somewhere?" -- you already do - you store it in `salt` field. – zerkms Dec 16 '10 at 03:50
  • @RageZ: he is using mysqli ;-P – zerkms Dec 16 '10 at 03:53
  • hahaahha sorry, I posted the wrong code. Everything is right except for i was supposed to take that out in the code(storing the salt that is), but I am assuming I have to store the salt in order for this to work. That was my actual question. Sorry. – mcbeav Dec 16 '10 at 03:54
  • I was using PDO but i found out PDO does not support SSL, any suggestions? or will mysqli work fine? – mcbeav Dec 16 '10 at 03:55
  • @RageZ: and, yes, I also don't know any reason to use mysqli instead of PDO ;-) – zerkms Dec 16 '10 at 03:55
  • also, i need to sanitize the username. What could I use? I am new to the whole PDO, prepared statement thing. I learned from what i now know is outdated PHP. i would have used mysql_escape_string, but i dont know if that still will work with this. – mcbeav Dec 16 '10 at 03:57
  • @mcbeav: mysqli PDO use place holder so you don't have to worry about escaping. – RageZ Dec 16 '10 at 03:59
  • so there is no reason to have to worry about escaping? I would use PDO but it does not support SSL, so mysqli is ok to use for this? – mcbeav Dec 16 '10 at 04:01
  • @mcbeav: you want to encrypt the data between your php application and mysql may I ask why? – RageZ Dec 16 '10 at 04:03
  • maybe i don't entirely understand the question, but I am just in the process of learning PHP security, PDO, prepared statements. I am attempting to create a secure login system, basically for the purposes of learning. – mcbeav Dec 16 '10 at 04:06
  • @mcbeav: "so there is no reason to have to worry about escaping?" --- not manually at least http://php.net/manual/en/mysqli.prepare.php – zerkms Dec 16 '10 at 04:06
2

Do the same work:

$hash = hash('sha256', $row['salt'] . hash('sha256', $pass) . $pass);
if ($row['password'] == $hash) {
    // the password is correct
}

Where $row has been taken from the database according to the username, and $pass is the password retrieved from the form.

Also, it is pointless to include password in the hash twice: hashed and plain text one

$hash = hash('sha256', $salt . $pass); // this would be enough
zerkms
  • 249,484
  • 69
  • 436
  • 539
  • @zerkms: it is not really pointless because it increase the complexity to crack the password. since you have to do two pass of sha256. Plus it would make difficult to crack even short password, since the hash is always a long string no matter what. – RageZ Dec 16 '10 at 03:53
  • thanks! i was unaware of that. The code was changed to actually not store the salt, didn't see that i posted the wrong code, but I'm assuming that I have to store the salt here in order for things to work. Is storing the salt in the DB going to make this less secure? – mcbeav Dec 16 '10 at 03:53
  • @RageZ: indeed in the part, that 2 calculations is slower than 1, but do not indeed that longer string is more secured (since it was prepared from the same data). – zerkms Dec 16 '10 at 03:54
  • @mcbeav: http://stackoverflow.com/questions/4457097/php-and-mysql-salt-security-question – zerkms Dec 16 '10 at 03:55
  • 1
    @zerkms: yeah you are right at least it make it more complex but not more secure I suppose. – RageZ Dec 16 '10 at 03:58
  • @zerkms thanks for the link. I really appreciate the help here. I am relatively new to PHP and completely new to security. I learned from what i now know are outdated PHP books. – mcbeav Dec 16 '10 at 04:00
  • thanks for all the help everyone. I really appreciate all of this. – mcbeav Dec 16 '10 at 04:00
1

Issues:

1) Your method for creating a password hash of the hash+salt is non-traditional. This isn't strictly an issue, it just isn't what it seemed like you wanted. zerkms made this point pretty clearly.

2) Your database insert requires either that username is a unique column and is missing some exception handling, or it is vulnerable to a race that will result in multiple users with the same username and different passwords (and different IDs if that is a key)

Slartibartfast
  • 1,694
  • 9
  • 8
  • i am sorry i am not sure if i completely understand your answer. For the second part, are you saying that the function checking to see if the username is in use is not written correctly? If so, any idea on how to fix this? I am new to mysqli and PDO although this is mysqli. and as for the first part, do you think this may cause any issues with anything? maybe performace? – mcbeav Dec 16 '10 at 04:03