SQL Injection Defense

SQL injection defenses beyond basics: binding, whitelisting, and patterns.

On this page

What SQL Injection Is

SQL injection happens when attackers control query structure via untrusted input. The only correct defense is: prepared statements + parameter binding. Never build SQL by concatenating user input.

The Dangerous Pattern

<?php
$id = $_GET["id"] ?? "0";
// Dangerous:
$sql = "SELECT id, title FROM items WHERE id = " . $id;

The Correct Pattern (Bind Values)

<?php
$id = (int)($_GET["id"] ?? 0);

$stmt = $pdo->prepare("SELECT id, title FROM items WHERE id = ?");
$stmt->execute([$id]);

$row = $stmt->fetch();

LIKE Queries Safely

You can still use LIKE with binding. You just bind the full pattern.

<?php
$q = $_GET["q"] ?? "";

$stmt = $pdo->prepare("SELECT id, title FROM items WHERE title LIKE ? LIMIT 20");
$stmt->execute(["%" . $q . "%"]);

Whitelist for ORDER BY and Identifiers

You cannot bind column names. Use a whitelist map for sorting/filtering identifiers.

<?php
$sort = $_GET["sort"] ?? "new";
$map = [
  "new" => "id DESC",
  "old" => "id ASC",
  "title" => "title ASC",
];

$orderBy = $map[$sort] ?? $map["new"];

$sql = "SELECT id, title FROM items ORDER BY " . $orderBy . " LIMIT 20";
$rows = $pdo->query($sql)->fetchAll();

Production Tip

Bind every user-provided value. Whitelist identifiers. Add validation (int casting, length limits). Log suspicious patterns and rate limit abuse-prone endpoints.