Мога ли да използвам подготвен израз на PDO, за да обвържа идентификатор (име на таблица или поле) или ключова дума за синтаксис?
За съжаление, подготвеното изявление може да представлява само литерал на данни. И така, много често срещан капан е заявка като тази:
$opt = "id";
$sql = "SELECT :option FROM t WHERE id=?";
$stm = $pdo->prepare($sql);
$stm->execute(array($opt));
$data = $stm->fetchAll();
В зависимост от настройките на PDO, тази заявка ще доведе до грешка (в случай на използване на реални подготвени изрази) или просто литерален низ 'id'
в набора от полета (в случай на емулирана подготовка).
Така че разработчикът трябва сам да се погрижи за идентификаторите - PDO предлага без помощ по този въпрос.
За да направите динамичния идентификатор безопасен, трябва да следвате 2 строги правила:
- за да форматирате правилно идентификатора
- за да го проверите спрямо твърдо кодиран бял списък .
За да форматирате идентификатор, трябва да приложите тези 2 правила:
- Включете идентификатора в обратни тикчета.
- Избягайте от обратните тикчета вътре, като ги удвоите.
След такова форматиране е безопасно да вмъкнете променливата $table в заявката. И така, кодът ще бъде:
$field = "`".str_replace("`","``",$field)."`";
$sql = "SELECT * FROM t ORDER BY $field";
Въпреки това, въпреки че такова форматиране би било достатъчно за случаи като ORDER BY, за повечето други случаи има възможност за различен вид инжектиране:позволявайки на потребителя да избере таблица или поле, което може да види, можем да разкрием някои чувствителна информация, като парола или други лични данни. Така че винаги е по-добре да проверявате динамичните идентификатори спрямо списък с разрешени стойности. Ето кратък пример:
$allowed = array("name","price","qty");
$key = array_search($_GET['field'], $allowed);
$field = $allowed[$key];
$query = "SELECT $field FROM t"; //value is safe
Правилата за ключови думи са едни и същи, но разбира се няма налично форматиране - по този начин е възможно само белият списък и трябва да се използва:
$dir = $_GET['dir'] == 'DESC' ? 'DESC' : 'ASC';
$sql = "SELECT * FROM t ORDER BY field $dir"; //value is safe
Вижте също тази бележка, допусната от потребителя в документацията на PHP:Бележка на потребителя за PDO::quote