PHP Programming Security Tips and Tricks

Sunday, July 30, 2006

User Passwords in PHP

So most of the times, you need to authenticate users against your database. But how do you go about encrypting the password? PHP provides many native ways to create a hash, but what is the best method?

MD5 is one of the most common, but have been susceptible to brute force attacks now. This of course assumes weak passwords.

Crypt selects the *best* method available from a pre-defined list, and accepts a salt.

SHA1 creates a better hash than MD5.

The best hash method is generally SHA1. But you need to take it one (or more) steps further. It should be common practice to create a salt that you use to create the hash. Below is an example.


$pw="1mc00l";
$salt="5X93.CC";
$userPass=sha1($pw.$salt);


But where does the salt come from? Is it generated per user, or is it global for the application? And how do you authenticate it? In most cases, you query the DB and check if the hashed password equals the database field. Below is an example for a global application salt.


$pw="1mc00l";
$salt="5X93.CC";
$userPass=sha1($pw.$salt);
$username="phacro";
$sql="SELECT Username,UserID,Email from USERS where Username='".mysql_real_escape_string($username)."' and Userpassword='".mysql_real_escape_string($userPass)."'";
$res=mysql_query($sql);
if(mysql_num_rows($res)>0){
//found user
}


This isn't a bad method, and you must make sure the file the salt is in can not be accessed via a web page (store beneath document root). But what about a salt that is generated for each user?


$pw="1mc00l";
$username="phacro";
$sql="SELECT Username,UserID,Email,Usersalt,Userpassword from USERS where Username='".mysql_real_escape_string($username)."'";
$res=mysql_query($sql);
if(mysql_num_rows($res)>0){
    $salt=mysql_result($res,0,"Usersalt");
    $dbPW=mysql_result($res,0,"Userpassword");
    if($dbPW!=sha1($pw.$salt))
    {
       //bad password
    }
}


When you create a new user, you create a random salt and store it in the field. You can't compare the hash in the SQL field, so you must do it on the code level by getting the hash from the DB.


Ok...so the two examples are better than just storing the hashed value in the database. The optimal method is to do a combination of both.


$pw="1mc00l";
$username="phacro";
$siteSalt="!2%C(9b";
$sql="SELECT Username,UserID,Email,Usersalt,Userpassword from USERS where Username='".mysql_real_escape_string($username)."'";
$res=mysql_query($sql);
if(mysql_num_rows($res)>0){
    $salt=mysql_result($res,0,"Usersalt");
    $dbPW=mysql_result($res,0,"Userpassword");
    if($dbPW!=sha1($siteSalt.$pw.$salt))
    {
       //bad password
    }
}



As you can see there's an order you can use for the salts and password when creating the hash. Make sure you remember it and use it when you create the user and authenticate them.

0 Comments:

Post a Comment

Links to this post:

Create a Link

<< Home