Kan jag använda en PDO-förberedd sats för att binda en identifierare (ett tabell- eller fältnamn) eller ett syntaxnyckelord?
Tyvärr kan förberedda uttalanden endast representera en bokstavlig data. Så en mycket vanlig fallgrop är en fråga som denna:
$opt = "id";
$sql = "SELECT :option FROM t WHERE id=?";
$stm = $pdo->prepare($sql);
$stm->execute(array($opt));
$data = $stm->fetchAll();
Beroende på PDO-inställningarna kommer denna fråga att resultera med antingen fel (vid användning av riktiga förberedda satser) eller bara en bokstavlig sträng 'id'
i fältuppsättningen (vid emulerade förberedelser).
Så en utvecklare måste ta hand om identifierare själv - PDO erbjuder ingen hjälp för den här delen.
För att göra en dynamisk identifierare säker måste man följa 2 strikta regler:
- för att formatera identifieraren korrekt
- för att verifiera den mot en hårdkodad vitlista .
För att formatera en identifierare måste man tillämpa dessa två regler:
- Bislut identifierare i backticks.
- Flyg backticks inuti genom att dubbla dem.
Efter sådan formatering är det säkert att infoga variabeln $table i frågan. Så, koden skulle vara:
$field = "`".str_replace("`","``",$field)."`";
$sql = "SELECT * FROM t ORDER BY $field";
Men även om en sådan formatering skulle räcka för fall som ORDER BY, för de flesta andra fall finns det en möjlighet för en annan typ av injektion:att låta en användare välja en tabell eller ett fält de kan se, kan vi avslöja några känslig information, som lösenord eller annan personlig information. Så det är alltid bättre att kontrollera dynamiska identifierare mot en lista med tillåtna värden. Här är ett kort exempel:
$allowed = array("name","price","qty");
$key = array_search($_GET['field'], $allowed);
$field = $allowed[$key];
$query = "SELECT $field FROM t"; //value is safe
För sökord är reglerna desamma, men naturligtvis finns ingen formatering tillgänglig - därför är endast vitlista möjlig och bör användas:
$dir = $_GET['dir'] == 'DESC' ? 'DESC' : 'ASC';
$sql = "SELECT * FROM t ORDER BY field $dir"; //value is safe
Se även denna användarbidrag i PHP-dokumentationen:Användaranteckning om PDO::quote