PHP: PDO prepared statements not preventing all injection?

posée 10 days ago156 vuesen

1

I use PDO prepared statements everywhere but a security review flagged a query where the table name is dynamic. How do I safely handle dynamic identifiers?

🤖 Diagnostic IA

Généré par IA. Ce n'est pas une réponse — la communauté ci-dessous le confirme ou le corrige. Vérifiez toujours avant de vous y fier.

posée 10 days ago

3 réponses

0
Réponse acceptée

Short answer

Prepared statement placeholders (? or :name) only work for values (data), not for identifiers like table or column names. PDO has no built-in way to bind an identifier — that's why your dynamic table name query isn't actually protected, even though you're "using prepared statements."

What to do instead

  1. Whitelist validation — the safest and most common approach. Only allow table names that exist in a known, hardcoded list:
$allowedTables = ['users', 'orders', 'invoices'];
 
if (!in_array($tableName, $allowedTables, true)) {
    throw new InvalidArgumentException('Invalid table name');
}
 
$sql = "SELECT * FROM `$tableName` WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $id]);
  1. If you truly can't whitelist, at minimum strictly validate the format (e.g. only allow [A-Za-z0-9_]+ matching an existing schema table) and quote the identifier properly for your DB engine (backticks for MySQL, double quotes for Postgres). This is weaker than a whitelist and still risky if validation is incomplete — whitelist is strongly preferred.

  2. Never concatenate user input directly into the identifier position and never try to "escape" it the same way you'd escape a value — identifiers aren't values, so PDO::quote() is not designed for this and shouldn't be relied on for table/column names.

Bottom line

Values → use prepared statement placeholders. Identifiers (table/column names) → validate against a whitelist before building the SQL string.

Connectez-vous pour dire si ça a marché.

answered a day ago
3

Server Action for form mutations tied to your own DB and revalidation; Route Handler when you need a stable HTTP endpoint (webhooks, external/mobile clients, non-React consumers). Both must re-validate auth server-side.

Connectez-vous pour dire si ça a marché.

answered 10 days ago
2

Prepared statements only parameterize values, not identifiers. For a dynamic table name, whitelist against a known set:

$allowed = ['orders', 'invoices'];
if (!in_array($table, $allowed, true)) throw new InvalidArgumentException();

Connectez-vous pour dire si ça a marché.

answered 10 days ago

Sign in and verify your email to post an answer.