Create a new table in your database by saving this file and then importing it in PHPMyAdmin.  You should now have a very simple table called member in your database.

Copy this code into the central block of PHP on a new page called sqlinjectionform.php (you may need to include or add the database connection lines if they are missing):

if (!$_POST) {

    <h1>Log in here</h1>

    <form method="post" action="<?php echo $_SERVER["PHP_SELF"]; ?>">
        <p><label for="username">Type your username here: </label><input type="text" name="username" id="username"></p>
        <p><label for="password">Type your password here: </label><input type="text" name="password" id="password"></p>						   
        <input type="submit" name="submit">
} else {
    $passwordCheckQuery="SELECT username FROM member WHERE username='$username' AND password='$password';";
    // echo "<p>The query now reads: $passwordCheckQuery</p>";
    $passwordCheckResult=mysqli_query($dbconnection, $passwordCheckQuery) or die("Broke: ".mysqli_error($dbconnection));
        echo "Welcome";
    } else {
        echo "Not logged in";

Test it by using sara and sara as username and password.  It should welcome you.  Try incorrect log in details and it should reject you.

Make sure you understand that:

The injection

All that was preparation.  Now enter anything into the username field and this into the password field:

' OR 1='1

Even without matching records in the database the log in works. 

Find the line in sqlinjectionform.php which is commented out.  Uncomment the line by removing the two slashes.  Try the page again and you can see that the stuff typed into the password field mixed with the query in the PHP page created a different query where records will always be found in the database because 1 is always equal to 1.  It now says to let someone in:

WHERE username is something AND password is nothing or just where 1=1

With such a simple attack you can foil it by just amending one line of code.  However, that will not stop more sophisticated attacks so don't rely on it (the simple fix would be to use == instead of >= in the second if).  There should always be more than one result so the if condition returns false.  It is worth doing this in all code anyway because more specific if conditions mean less chance of you messing up.

Prevention - mysqli_real_escape_string()

The correct solution is to always use the function mysqli_real_escape_string().  You currently have two lines which put the form data into variables:


change them to this:

$username=mysqli_real_escape_string($dbconnection, $_POST["username"]);
$password=mysqli_real_escape_string($dbconnection, $_POST["password"]);

This function looks at the user data and escapes any dangerous characters (by putting a \ in front of it just as you did with PHP and quotes).  The potentially dangerous characters (' being the one here) are now ignored by the PHP script interpreter and are sent direct to the server for comparison with the database data.

Other user data

Form data is just one example of how a user can inject SQL.  $_GET data (in the URL) can be edited by a user so cannot be trusted.  Cookie data is easily changed.  Session data could be changed if the server is wrongly configured.  Data from a file or a database cannot be edited by a normal user but was it made safe before it was stored?  It might be best not to trust it unless you made it safe yourself (using mysqli_real_escape_string) and put it there.


It shouldn't take much imagination to see that a user might be able to do lots of things as well as get logged in.  Once logged in they might be able to do lots but even if normal users cannot access the whole site there are some things they can do by forcing queries to select (or delete) more than intended (like a bank site which shows transactions for every user instead of just you).

You can also use similar techniques to inject even more dangerous commands in SQL as illustrated here.