SQL Injection
SQL injection is what happens when user input is concatenated into a query as raw text — the attacker can change the meaning of the SQL the app intended to run.
The vulnerable pattern
PHP — DON'T
// $_POST['email'] is attacker-controlled $sql = "SELECT * FROM users WHERE email = '" . $_POST['email'] . "'"; mysqli_query($conn, $sql);
If email is ' OR 1=1 --, the resulting SQL becomes:
SQL
SELECT * FROM users WHERE email = '' OR 1=1 -- '
Now it returns every row. With UNION the attacker can leak other tables; with ;DROP they can destroy them.
The fix — parameterised queries
PHP — Safe
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$_POST['email']]);
The driver sends the SQL and the parameter separately. The DB never tries to parse the parameter as SQL — injection becomes impossible.
Same idea, other languages
| Language | Form |
|---|---|
| Python (psycopg) | cur.execute("… WHERE email = %s", (email,)) |
| Node (pg) | client.query("… WHERE email = $1", [email]) |
| Java (JDBC) | PreparedStatement + setString |
| Laravel Eloquent | User::where('email', $email) — auto-binds. |
Defence in depth
- Use the app's ORM or query builder — most bind automatically.
- Give the app's DB user the least privileges it needs (no
DROP, noGRANT). - Use a WAF / IDS for anomaly detection.
- Treat all input as hostile, including from authenticated users.
Tip: If you ever find yourself thinking "I'll just escape the quotes myself", stop. There's no safe hand-roll. Use the driver's bound parameters every single time.
Example
Example
-- Use parameters, never concatenate user input: SELECT * FROM users WHERE email = ? AND password_hash = ?;Try it Yourself »
Exercise
The fix for SQL injection is to use…
statements (with bound parameters)
Eight letters; the kind of statement that binds parameters.
Discussion
Loading…