flawopen.com/SQL Injection в PHP/mysqli и PDO
MySQLi и PDO: безопасные подготовленные запросы
Подготовленный запрос сохраняет SQL-инструкции неизменными и передаёт значения отдельно — как заполнение подписанных полей. Это умеют PDO и MySQLi. Безопасность зависит от правильной привязки значений, а не названия библиотеки.
Один запрос с подготовкой в обеих API
$userId = $_GET['id']; $sql = "SELECT id, email FROM users WHERE id = " . $userId; // Both calls execute the already-built SQL string: $rows = $mysqli->query($sql); $rows = $pdo->query($sql);
// PDO $stmt = $pdo->prepare( "SELECT id, email FROM users WHERE id = :id" ); $stmt->execute(["id" => $userId]); // MySQLi $stmt = $mysqli->prepare( "SELECT id, email FROM users WHERE id = ?" ); $stmt->bind_param("i", $userId); $stmt->execute();
Портируемость между базами — главное отличие PDO
PDO даёт общий интерфейс для нескольких драйверов; MySQLi предназначен для MySQL и MariaDB. PDO сам по себе не делает SQL переносимым: диалекты, драйверы и функции отличаются.
PDO поддерживает именованные placeholder, например :id, и позиционные ? в зависимости от драйвера; не смешивайте их. MySQLi использует позиционные ?. Оба связывают значения, но не имена таблиц/столбцов, ключевые слова и сортировку.
Драйверы PDO используют нативную или эмулируемую подготовку. В MySQL PDO::ATTR_EMULATE_PREPARES управляет эмуляцией, если она поддерживается; драйвер может перейти к ней при отсутствии нативной подготовки. Следуйте документации драйвера. Эта настройка не защищает интерполированный SQL: фиксируйте текст и связывайте значения в любом режиме.
Правила защиты от SQL Injection для обеих библиотек
Вызывайте prepare() и связывайте каждое недоверенное значение. Оставляйте SQL-синтаксис фиксированным; динамические идентификаторы выбирайте из строгой серверной карты или конечного набора запросов. Подготовка не разрешает доступ к строке: при необходимости ограничьте запрос аутентифицированным пользователем. В LIKE привязка предотвращает SQL-инъекцию, но % и _ остаются подстановочными знаками без экранирования для буквального поиска.
Выбор между PDO и MySQLi
- ✓Выбирайте PDO для общего API разных драйверов; при миграции проверьте диалект SQL и поведение драйвера.
- ✓Выбирайте MySQLi для приложений только на MySQL/MariaDB, которым нужна его специфичная API.
- ✓В обоих случаях ищите интерполяцию, конкатенацию и динамические идентификаторы; связывайте значения, а записи авторизуйте отдельно.
Частые вопросы
Нет. Обе библиотеки безопасно связывают значения при подготовленном запросе. Имена могут быть читабельнее, но не связывают идентификаторы и не заменяют авторизацию.
Не как общее правило. Поддержка и fallback зависят от драйвера. Изучите документацию и требования приложения. В любом режиме фиксируйте SQL-структуру и передавайте значения параметрами.
Нет. Параметры представляют значения, а не идентификаторы или SQL-ключевые слова. Сопоставляйте выбор клиента с конечным набором доверенных фрагментов на сервере.
Источники
- Руководство PHP — подготовленные запросы PDO
- Руководство PHP — подготовленные запросы MySQLi
- Руководство PHP — PDO::setAttribute и эмулируемая подготовка
- FlawOpen — SQL Injection в PHP