PDO: параметры защищают значения, но не имена столбцов
Что можно передавать параметрами PDO, как выбирать столбец сортировки и где отдельно проверять доступ к данным.
- ЗначенияПодставляем через параметры PDO
- Имена полейВыбираем из разрешённого списка
- Связанные измененияОбъединяем в явную транзакцию
Параметр PDO хорошо подходит для имени пользователя или номера проекта, но не для имени столбца в ORDER BY. Параметры передают значения, а не части синтаксиса SQL. Разберём безопасную подстановку значений, выбор сортировки из разрешённого списка и отдельную проверку доступа к проекту.
Передаём значение параметром
$pdo = new PDO($dsn, $user, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
]);
$query = $pdo->prepare(
'SELECT id, title FROM tasks WHERE project_id = :project'
);
$query->execute(['project' => $projectId]);
$rows = $query->fetchAll(PDO::FETCH_ASSOC);Пример предполагает поддерживающий эти настройки драйвер и заранее подготовленное соединение. Сам идентификатор проекта всё равно должен проверяться на уровне доступа: защита от SQL-инъекции не означает, что пользователь вправе читать любой проект.
Сортировку выбираем из известных вариантов
$columns = ['date' => 'created_at', 'title' => 'title'];
$requestedSort = $_GET['sort'] ?? 'date';
$sort = is_string($requestedSort)
? ($columns[$requestedSort] ?? 'created_at')
: 'created_at';
$query = $pdo->prepare(
"SELECT id, title FROM tasks WHERE project_id = :project ORDER BY $sort"
);
$query->execute(['project' => $projectId]);В SQL попадает значение из серверного массива, а не произвольный текст запроса. Для ASC и DESC нужен такой же ограниченный выбор. Не пытайтесь заменить имя столбца на :sort: сервер воспримет параметр как значение, а не как требуемую структуру SQL.
Когда нужна транзакция
Если несколько изменений должны пройти вместе, начните транзакцию, выполните операции и завершите её commit. При исключении откатите активную транзакцию и обработайте ошибку. Не держите её открытой, пока пользователь отвечает на вопрос или внешний сервис выполняет сетевой запрос.
Проверьте допустимую сортировку, неизвестное имя, параметр sort[]=title и чужой проект. Первые три случая должны выбрать разрешённый столбец или безопасное значение по умолчанию; чужой проект — получить отказ независимо от безопасности SQL. Подробности ошибки оставляйте в закрытом журнале; пользователю не нужны DSN, конфигурация и внутренние пути.
