Saturday, March 13, 2010

12:15 AM

If you are developing a password-protected web site, you have to make a decision about how to store user password information securely.

What is "secure," anyway? Realize that the data in your database is not safe. What if the password to the database is compromised? Then your entire user password database will be compromised as well. Even if you are quite certain of the security of your database, your users' passwords are still accessible to all administrators who work at the Web hosting company where your database is hosted. Scrambling the passwords using some home-brewed algorithm may add some obscurity but not true "security." Another approach would be to encrypt all passwords in your database using some industry-standard cipher, such as the Message-Digest Algorithm 5 (MD5).
MD5 encryption is a one-way hashing algorithm. Two important properties of the MD5 algorithm are that it is impossible to revert back an encrypted output to the initial, plain-text input, and that any given input always maps to the same encrypted value. This ensures that the passwords stored on the server cannot be deciphered by anyone. This way, even if an attacker gains reading permission to the user table, it will do him no good.
MD5 does have its weaknesses. MD5 encryption is not infallible: if the password is not strong enough, a brute force attack can still reveal it. So, you can ask: "Why should I use MD5 if I know it is not the most secure?" The answer is fairly straightforward: it's fast, it's easy, and it can be powerful if salted. The greatest advantage of MD5 is its speed and ease of use.
It is vitally important to understand that password encryption will not protect your website, it can protect your passwords only. If your website does not have sufficient protection, password encryption will not make it safe from cracking. If your system has been cracked, a hacker can inflict a irreparable damage to it and also gain an access to confidential information, including passwords database. But if you store this information encrypted, hackers practically cannot make use of it. Cracking an encrypted password takes a large amount of time and processing power, even on today's computers.
So, let's start. First of all, you need to add a new account to your database. The following code allows to do it.
<?php
define("DB_SERVER", "localhost");
define("DB_USER", "your_name");
define("DB_PASS", "your_pass");
define("DB_NAME", "your_db");
define("TBL_USERS", "users_table_name");

$connection = mysql_connect(DB_SERVER, DB_USER, DB_PASS) or die(mysql_error());
mysql_select_db(DB_NAME, $connection) or die(mysql_error());

...

function addNewUser($username, $password){
   global $connection;
   $password = md5($password);
   $q = "INSERT INTO ".TBL_USERS." VALUES ('$username', '$password')";
   return mysql_query($q, $connection);
}
?>

Now, when a new user completes the registration form, his password will be encrypted automatically.
After that we should write code that validates a given username/password pair.
<?php
function checkUserPass($username, $password){
   global $connection;
     
   $username = str_replace("'","''",$username)
   $password = md5($password);
   // Verify that user is in database
   $q = "SELECT password FROM ".TBL_USERS." WHERE username = '$username'";
   $result = mysql_query($q, $connection);
   if(!$result || (mysql_numrows($result) < 1)){
     return 1; //Indicates username failure
   }     
   
   // Retrieve password from result
   $dbarray = mysql_fetch_array($result);
   
   // Validate that password is correct
   if($password == $dbarray['password']){
      return 0; 
//Success! Username and password confirmed
   }
   else{
      return 1; 
//Indicates password failure
   }
}
?>

And what if you already have users' database ready and want to start using encrypted passwords? To do it, you need to write encypt.php script with the following code and run it in your browser.
<?php
define("DB_SERVER", "localhost");
define("DB_USER", "your_name");
define("DB_PASS", "your_pass");
define("DB_NAME", "your_db");
define("TBL_USERS", "users_table_name");
define("FLD_USER", "username_field_name");
define("FLD_PASS", "password_field_name");

set_magic_quotes_runtime(0);

$connection = mysql_connect(DB_SERVER, DB_USER, DB_PASS) or die(mysql_error());
mysql_select_db(DB_NAME, $connection) or die(mysql_error());

$q = "SELECT ".FLD_PASS.",".FLD_USER." FROM ".TBL_USERS."";
$result = mysql_query($q, $connection);

$total=0;
$enc=0;

$doencrypt=false;
if (@$_REQUEST["do"]=="encrypt")
  $doencrypt=true;

while($data = mysql_fetch_array($result))
{
  if ($doencrypt)
  {
    $total++;
    if (!encrypted($data[0]))
    {
      $q="UPDATE ".TBL_USERS." SET ".FLD_PASS."='".md5($data[0])."' where ".FLD_USER."='".
      str_replace("'","''",$data[1])."'";
      mysql_query($q, $connection);
    }
   $enc++;
 }
 else
 {
   $total++;
   if (encrypted($data[0]))
     $enc++;
 }
}

function encrypted($str)
{
  if (strlen($str)!=32)
    return false;

  for($i=0;$i<32;$i++)
    if ((ord($str[$i])<ord('0') || ord($str[$i])>ord('9')) && (ord($str[$i])<ord('a') || ord($str[$i])>ord('f')))
     return false;

return true;
}
?>

<html>
<head><title>Encrypt passwords</title></head>
<body>
Total passwords in the table - <?php echo $total; ?><br>
<?php if($enc==$total && $total>0) { ?>
All passwords are encrypted.
<?php } else if($total>0) { ?>
Unencrypted - <?php echo $total-$enc; ?><br><br>
Click "GO" to encrypt <?php echo $total-$enc; ?> passwords.<br>
WARNING! There will be no way to decipher the passwords.<br>
<input type=button value="GO" onclick="window.location='encrypt.php?do=encrypt';">
<?php } ?>
</body>
</html>

0 comments: