Web Security Basics: Not Getting Owned SQL Injection: Never Build Queries by Concatenation
1 / 5
Next
SQL Injection: Never Build Queries by Concatenation ~16min

The broken code

$sql = "SELECT * FROM users WHERE email = '$email'";

Someone submits ' OR '1'='1 and the query becomes WHERE email = '' OR '1'='1', true for every row. With a login, that is a login as the first user in the table, usually the administrator.

Why escaping is not the answer

Escaping quotes by hand fails on charset edge cases, on numeric contexts, and on the day someone forgets. The fix is structural: send the query and the data SEPARATELY, so the data can never be read as SQL.

$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);

Now ' OR '1'='1 is just a string that matches no email. It is not cleverly escaped. It is never parsed as SQL at all.

What placeholders cannot do

They bind VALUES, not identifiers. A table or column name cannot be a placeholder. If a sort column comes from the URL, validate it against an allow-list:

$allowed = ['name','price','created_at'];
$sort = in_array($_GET['sort'] ?? '', $allowed, true) ? $_GET['sort'] : 'name';

One more

Turn off emulated prepares, ATTR_EMULATE_PREPARES => false, so the database does the parameterising rather than the driver doing string interpolation on your behalf.

Tasks
Preview