FlawOpen

flawopen.com/SQL Injection в PHP/mysqli и PDO

MySQLi и PDO: безопасные подготовленные запросы

Справочная страница
Краткий ответ

Подготовленный запрос сохраняет SQL-инструкции неизменными и передаёт значения отдельно — как заполнение подписанных полей. Это умеют PDO и MySQLi. Безопасность зависит от правильной привязки значений, а не названия библиотеки.

Один запрос с подготовкой в обеих API

НЕБЕЗОПАСНО — SQL с данными запроса
$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);
БЕЗОПАСНО — связывайте значения в обеих API
// 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

PDO даёт общий интерфейс для нескольких драйверов; MySQLi предназначен для MySQL и MariaDB. PDO сам по себе не делает SQL переносимым: диалекты, драйверы и функции отличаются.

Стили placeholder различаются

PDO поддерживает именованные placeholder, например :id, и позиционные ? в зависимости от драйвера; не смешивайте их. MySQLi использует позиционные ?. Оба связывают значения, но не имена таблиц/столбцов, ключевые слова и сортировку.

Режим подготовки PDO зависит от драйвера

Драйверы PDO используют нативную или эмулируемую подготовку. В MySQL PDO::ATTR_EMULATE_PREPARES управляет эмуляцией, если она поддерживается; драйвер может перейти к ней при отсутствии нативной подготовки. Следуйте документации драйвера. Эта настройка не защищает интерполированный SQL: фиксируйте текст и связывайте значения в любом режиме.

Правила защиты от SQL Injection для обеих библиотек

Вызывайте prepare() и связывайте каждое недоверенное значение. Оставляйте SQL-синтаксис фиксированным; динамические идентификаторы выбирайте из строгой серверной карты или конечного набора запросов. Подготовка не разрешает доступ к строке: при необходимости ограничьте запрос аутентифицированным пользователем. В LIKE привязка предотвращает SQL-инъекцию, но % и _ остаются подстановочными знаками без экранирования для буквального поиска.

Выбор между PDO и MySQLi

Частые вопросы

Именованные placeholder PDO безопаснее знаков ? в MySQLi?

Нет. Обе библиотеки безопасно связывают значения при подготовленном запросе. Имена могут быть читабельнее, но не связывают идентификаторы и не заменяют авторизацию.

Нужно ли всегда отключать эмулируемую подготовку PDO?

Не как общее правило. Поддержка и fallback зависят от драйвера. Изучите документацию и требования приложения. В любом режиме фиксируйте SQL-структуру и передавайте значения параметрами.

Может ли подготовленный запрос связать имя таблицы или столбца?

Нет. Параметры представляют значения, а не идентификаторы или SQL-ключевые слова. Сопоставляйте выбор клиента с конечным набором доверенных фрагментов на сервере.

Источники

См. также SQL-инъекции (CWE-89): как они работают и как их предотвратить в любом языке — flawopen.com Защищает ли NHibernate от SQL-инъекций? NoSQL-инъекция в MongoDB: безопасные фильтры SQL Injection при числовых ID: риск? Что такое параметризованный запрос? Защищает ли Prisma $queryRaw от SQL-инъекций? Безопасна ли интерполяция в Rails where()?