Posso utilizzare un'istruzione preparata PDO per associare un identificatore (una tabella o un nome di campo) o una parola chiave di sintassi?
Sfortunatamente, l'istruzione preparata può rappresentare solo un valore letterale di dati. Quindi, una trappola molto comune è una query come questa:
$opt = "id";
$sql = "SELECT :option FROM t WHERE id=?";
$stm = $pdo->prepare($sql);
$stm->execute(array($opt));
$data = $stm->fetchAll();
Dipende dalle impostazioni PDO, questa query risulterà con un errore (in caso di utilizzo di istruzioni preparate reali) o solo una stringa letterale 'id'
nel fieldset (in caso di preparazioni emulate).
Quindi, uno sviluppatore deve occuparsi personalmente degli identificatori:PDO non offre nessun aiuto per questo.
Per rendere sicuro un identificatore dinamico, devi seguire 2 regole rigide:
- per formattare correttamente l'identificatore
- per verificarlo rispetto a una lista bianca hardcoded .
Per formattare un identificatore, è necessario applicare queste 2 regole:
- Raccogli l'identificatore nei backtick.
- Sfuggi ai backtick all'interno raddoppiandoli.
Dopo tale formattazione, è possibile inserire la variabile $table nella query. Quindi, il codice sarebbe:
$field = "`".str_replace("`","``",$field)."`";
$sql = "SELECT * FROM t ORDER BY $field";
Tuttavia, sebbene una tale formattazione sarebbe sufficiente per casi come ORDER BY, per la maggior parte degli altri casi esiste la possibilità di un diverso tipo di iniezione:lasciando che un utente scelga una tabella o un campo che può vedere, potremmo rivelare alcuni informazioni sensibili, come password o altri dati personali. Quindi, è sempre meglio controllare gli identificatori dinamici rispetto a un elenco di valori consentiti. Ecco un breve esempio:
$allowed = array("name","price","qty");
$key = array_search($_GET['field'], $allowed);
$field = $allowed[$key];
$query = "SELECT $field FROM t"; //value is safe
Per le parole chiave le regole sono le stesse, ma ovviamente non è disponibile alcuna formattazione, quindi è possibile e dovrebbe essere utilizzata solo la whitelist:
$dir = $_GET['dir'] == 'DESC' ? 'DESC' : 'ASC';
$sql = "SELECT * FROM t ORDER BY field $dir"; //value is safe
Vedi anche la nota che ha contribuito all'utente nella documentazione PHP:Nota utente su PDO::quote