Czy mogę użyć przygotowanej instrukcji PDO do powiązania identyfikatora (nazwy tabeli lub pola) lub słowa kluczowego składni?
Niestety, przygotowane zestawienie może reprezentować tylko literał danych. Tak więc bardzo częstą pułapką jest takie zapytanie:
$opt = "id";
$sql = "SELECT :option FROM t WHERE id=?";
$stm = $pdo->prepare($sql);
$stm->execute(array($opt));
$data = $stm->fetchAll();
W zależności od ustawień PDO, to zapytanie spowoduje błąd (w przypadku użycia prawdziwych przygotowanych instrukcji) lub tylko dosłowny ciąg 'id'
w zestawie pól (w przypadku emulowanych preparatów).
Tak więc programista musi sam zadbać o identyfikatory - PDO nie oferuje żadnej pomocy w tej sprawie.
Aby dynamiczny identyfikator był bezpieczny, należy przestrzegać 2 ścisłych zasad:
- aby poprawnie sformatować identyfikator
- aby zweryfikować go na zakodowanej na stałe białej liście .
Aby sformatować identyfikator, należy zastosować te 2 zasady:
- Zamknij identyfikator w zaznaczeniach.
- Ucieknij od kleszczy do środka, podwajając je.
Po takim formatowaniu można bezpiecznie wstawić zmienną $table do zapytania. Zatem kod będzie wyglądał następująco:
$field = "`".str_replace("`","``",$field)."`";
$sql = "SELECT * FROM t ORDER BY $field";
Jednak chociaż takie formatowanie wystarczyłoby w przypadkach typu ORDER BY, w większości innych przypadków istnieje możliwość innego rodzaju iniekcji:pozwalając użytkownikowi wybrać tabelę lub pole, które widzi, możemy ujawnić niektóre poufne informacje, takie jak hasło lub inne dane osobowe. Dlatego zawsze lepiej jest sprawdzać identyfikatory dynamiczne z listą dozwolonych wartości. Oto krótki przykład:
$allowed = array("name","price","qty");
$key = array_search($_GET['field'], $allowed);
$field = $allowed[$key];
$query = "SELECT $field FROM t"; //value is safe
W przypadku słów kluczowych zasady są takie same, ale oczywiście nie ma formatowania - w związku z tym możliwe jest tylko umieszczanie na białej liście i należy je stosować:
$dir = $_GET['dir'] == 'DESC' ? 'DESC' : 'ASC';
$sql = "SELECT * FROM t ORDER BY field $dir"; //value is safe
Zobacz także notatkę dodaną przez użytkownika w dokumentacji PHP:Uwaga użytkownika dotycząca PDO::quote