New PHP app - Salting and securing user passwords
I am setting up a new PHP app and would like to learn to salt and secure user password. I am unsure about which step during registration I need to do this at. Also, do I need to change my login forms as well?
if(isset($_POST['submit'])){
//protect and then add the posted data to variables
$username = protect($_POST['username']);
$password = protect($_POST['password']);
$passconf = protect($_POST['passconf']);
$email = protect($_POST['email']);
//check to see if any of the boxes were not filled in
if(!$username || !$password || !$passconf || !$email){
//if any weren't display the error message
echo "<center>You need to fill in all of the required filds!</center>";
}else{
//if all were filled in continue checking
//Check if the wanted username is more than 32 or less than 3 charcters long
if(strlen($username) > 32 || strlen($username) < 3){
//if it is display error message
echo "<center>Your <b>Username</b> must be between 3 and 32 characters long!</center>";
}else{
//if not continue checking
//select all the rows from out users table where the posted username matches the username stored
$res = mysql_query("SELECT * FROM `users` WHERE `username` = '".$username."'");
$num = mysql_num_rows($res);
//check if theres a match
if($num == 1){
//if yes the username is taken so display error message
echo "<center>The <b>Username</b> you have chosen is already taken!</center>";
}else{
//otherwise continue checking
//check if the password is less than 5 or more than 32 characters long
if(strlen($password) < 5 || strlen($password) > 32){
//if it is display error message
echo "<center>Your <b>Password</b> must be between 5 and 32 characters long!</center>";
}else{
//else continue checking
//check if the password and confirm password match
if($password != $passconf){
//if not display error message
echo "<center>The &开发者_运维技巧lt;b>Password</b> you supplied did not math the confirmation password!</center>";
}else{
//otherwise continue checking
//Set the format we want to check out email address against
$checkemail = "/^[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\.-][a-z0-9]+)*)+\\.[a-z]{2,}$/i";
//check if the formats match
if(!preg_match($checkemail, $email)){
//if not display error message
echo "<center>The <b>E-mail</b> is not valid, must be name@server.tld!</center>";
}else{
//if they do, continue checking
//select all rows from our users table where the emails match
$res1 = mysql_query("SELECT * FROM `users` WHERE `email` = '".$email."'");
$num1 = mysql_num_rows($res1);
//if the number of matchs is 1
if($num1 == 1){
//the email address supplied is taken so display error message
echo "<center>The <b>E-mail</b> address you supplied is already taken</center>";
}else{
//finally, otherwise register there account
//time of register (unix)
$registerTime = date('U');
//make a code for our activation key
$code = md5($username).$registerTime;
//insert the row into the database
$res2 = mysql_query("INSERT INTO `users` (`username`, `password`, `email`, `rtime`) VALUES('".$username."','".$password."','".$email."','".$registerTime."')");
//send the email with an email containing the activation link to the supplied email address
You absolutely must read this article: Enough with the rainbow tables.
Summary: If you're not using BCrypt, you're doing it wrong. No ifs, no buts. (This also means that all the suggestions to use MD5 or SHA-1 or SHA-512 or anything else are wrong too.)
As for when you do it, it should be sometime before you insert it into the DB but after you check it for errors.
Some suggestions though.
Instead of nesting the ifs during error checking so that if username fails, password doesn't get checked, and if password fails, passconf doesn't get checked try something like this:
$errors = array();
if(strlen($username) > 32 || strlen($username) < 3)
{
$errors['username'] = "Username must be between 3 and 32 characters.";
}
else
{
$res = mysql_query("SELECT * FROM `users` WHERE `username` = '".$username."'");
$num = mysql_num_rows($res);
if($num == 1)
{
$errors['username'] = "Username already exists!";
}
}
if(strlen($password) < 5 || strlen($password) > 32)
{
$errors['password'] = "Password must be between 5 and 32 characters.";
}
else if($password != $confpass)
{
$errors['password'] = "Passwords do not match.";
}
etc. etc. etc. so that each field is checked and errors returned if there are any. Then you do something like this at the end:
if(!count($errors)) //or if(count($errors) == 0)
{
//code to process login/registration/whatever Do password hashing here.
}
else
{
//There were errors, do something else
}
This way you get all errors, so you can tell the user everything that's wrong with their input at once, and the code isn't as deeply nested.
Also, the people having the flame war on what hashing algorithm to use above, just ignore them unless you're trying to create a US Government or Corporate application. No attackers will care enough to actually attack otherwise, unless your application gets popular enough to warrant an attack. It is important that you hash it in some way though.
SECURITY IS HARD. Don't do it yourself but let the exports figure it out. You could read there specs/implementations(if open):
- openid
- google friend connect
- facebook connect
- twitter single sign in
just to name a few options.
精彩评论