I’ve built this login form a while back, but now realize that it’s subject to MySQL injection because I didn’t escape any of the characters.
The login form:
if (isset($_POST['submit'])) { // upon submitting login form
$username = $_POST['username']; // must escape ALL user input
$password = sha1($_POST['password']);
if ($user->user_exists($username)) {
if ($result = $user->authenticate($username, $password)) {
$user_array = mysql_fetch_array($result);
$session->login($user_array); // login
redirect_to("members/homepage.php");
} else
$message = "Username/password combination is invalid.";
} else
$message = "User does not exist in the database.";
}
Abridged user class:
public function user_exists($username="") {
$sql = "SELECT * FROM " . self::$table_name . " WHERE username = '{$username}'";
$result = mysql_query($sql) or die("Query failed! " . mysql_error());
return (mysql_num_rows($result) > 0) ? true : false;
}
public static function authenticate($username="", $password="") {
global $database;
// $sql = "SELECT id, username FROM " . self::$table_name . " WHERE strcmp(username,'{$username}') = 0 AND strcmp(password,'{$password}') = 0";
$sql = "SELECT id, username FROM " . self::$table_name . " WHERE username = '{$username}' AND password = '{$password}'";
$result = mysql_query($sql) or die("Query failed! " . mysql_error());
return (mysql_num_rows($result) > 0) ? $result : false;
}
If I type in a quote mark in the login form
'
I get a MySQL error, meaning that my code is vulnerable to attack (the string is not being escaped properly). This makes sense because I did not escape any of the characters of the input username (I checked, this MySQL error is occuring not in the authenticate function, but in the user_exists function).
As you can see, the $username is directly input into the MySQL database; this is the security risk. A simple solution would be to escape the $username that is input.
Here’s my problem. If a cracker typed this into my login form:
x' OR 't=t
It is interpreted as an actual username (presumably as a string, because my default error message spits out that the Username/Password combination does not match).
Why is this being interpreted as a string when the single quote was being interpreted literally? Does the fact that a cracker can still type in a single quote put my login form at risk, when he cannot type in an actual SQL injection string, like the one above?
Help as always is greatly appreciated, thank you!
Edit:
The following code allows the username to validate:
23' OR '1=1
which is what I expected, and it is solved by applying the escaping function on the user input.
If the user typed that in, he’d be confronted with a “Username/password combination does not work.” Does the password field safely defend against MySQL injection, because the user requires both fields to type in any MySQL string (and the password field is hashed, meaning it won’t come out to anything coherent).