Ответ 1
Могу ли я использовать подготовленный оператор 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 правила:
- Введите идентификатор в backticks.
- Сбегите назад, удвоив их.
После такого форматирования безопасно вставить переменную $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