Problem
I’m just wondering if this code is good against SQL injection attacks. I don’t know how to check if is good. Also I would like to know if is good how I’m working or this is just bad practice?
<?php
if (isset($_POST['register'])) {
$username = $_POST["username"];
$email = $_POST["email"];
$password = $_POST["password"];
$salt = "Not important";
$password_hash = crypt($password, "$2y$". $salt);
if (strlen($username) > 20) {
echo "Username is too big";
}elseif (strlen($password) > 32) {
echo "Password is too big";
}elseif (strlen($email) > 100) {
echo "E-Mail is too big";
}elseif(strlen($username) == 0 || strlen($password) == 0 || strlen($email) == 0){
echo "Fill every field";
}
else{
$sth_username = $dbh->prepare("SELECT username FROM user WHERE username = :username");
$sth_username->bindParam(":username", $username);
$sth_email = $dbh->prepare("SELECT email FROM user WHERE email = :email");
$sth_email->bindParam(":email", $email);
$sth_username->execute();
$sth_email->execute();
if ($result = $sth_username->fetch(PDO::FETCH_OBJ)) {
print $result->username . "The username is already is use";
}elseif ($result = $sth_email->fetch(PDO::FETCH_OBJ)){
print $result->email . "That e-mail is already in use";
}else{
$sth = $dbh->prepare("INSERT INTO user (username, password, email, salt) VALUES (:username, :password, :email, :salt)");
$sth->bindParam(":username", $username);
$sth->bindParam(":password", $password_hash);
$sth->bindParam(":email", $email);
$sth->bindParam(":salt", $salt);
$sth->execute();
$sth = $dbh->prepare("INSERT INTO stats (strength,agility,intelligence) VALUES (10,10,10)");
$sth->execute();
echo "You have been registered";
}
}
?>
Solution
Looks O.K. to me as well, as far as the SQL injection goes.
However, I’d suggest checking the return value of $sth->execute();
, so you capture possible errors (i.e., DB being down).
You might also consider doing a case insensitive search for the existing usernames and e-mails, since “person@gmail.com” is the same address as “Person@GMail.com” and users “Person” and “person” are hard to distinguish.
I think empty($string)
is more advisable than strlen($string) == 0
.
Last, but not least, adding a “retype your password” field would be a good security against user mistyping what he wants for a password and then ending with a useless account (or having to use “I forgot my password” before the very first login).