Kan ik een door een PDO voorbereide instructie gebruiken om een identifier (een tabel- of veldnaam) of een syntaxissleutelwoord te binden?
Helaas kan een voorbereide verklaring alleen een data-letterlijk vertegenwoordigen. Een veel voorkomende valkuil is dus een zoekopdracht als deze:
$opt = "id";
$sql = "SELECT :option FROM t WHERE id=?";
$stm = $pdo->prepare($sql);
$stm->execute(array($opt));
$data = $stm->fetchAll();
Afhankelijk van de PDO-instellingen, zal deze zoekopdracht een fout opleveren (in het geval van gebruik van echte voorbereide instructies) of alleen een letterlijke tekenreeks 'id'
in de veldset (in het geval van geëmuleerde bereidingen).
Een ontwikkelaar moet dus zelf voor identifiers zorgen - PDO biedt geen hulp voor deze kwestie.
Om een dynamische identifier veilig te maken, moet men zich aan 2 strikte regels houden:
- identificatie correct opmaken
- om het te verifiëren aan de hand van een hardgecodeerde witte lijst .
Om een identifier te formatteren, moet men deze 2 regels toepassen:
- Identificatiecode tussen backticks insluiten.
- Ontsnap aan backticks door ze te verdubbelen.
Na een dergelijke opmaak is het veilig om de variabele $table in de query in te voegen. Dus de code zou zijn:
$field = "`".str_replace("`","``",$field)."`";
$sql = "SELECT * FROM t ORDER BY $field";
Hoewel een dergelijke opmaak voldoende zou zijn voor gevallen zoals ORDER BY, is er voor de meeste andere gevallen een mogelijkheid voor een ander soort injectie:een gebruiker een tabel of een veld laten kiezen dat hij kan zien, kunnen we enkele onthullen gevoelige informatie, zoals wachtwoord of andere persoonlijke gegevens. Het is dus altijd beter om dynamische id's te vergelijken met een lijst met toegestane waarden. Hier is een kort voorbeeld:
$allowed = array("name","price","qty");
$key = array_search($_GET['field'], $allowed);
$field = $allowed[$key];
$query = "SELECT $field FROM t"; //value is safe
Voor zoekwoorden zijn de regels hetzelfde, maar er is natuurlijk geen opmaak beschikbaar - dus alleen whitelisting is mogelijk en zou moeten worden gebruikt:
$dir = $_GET['dir'] == 'DESC' ? 'DESC' : 'ASC';
$sql = "SELECT * FROM t ORDER BY field $dir"; //value is safe
Zie ook deze door een gebruiker bijgedragen opmerking in de PHP-documentatie:Gebruikersopmerking over PDO::quote