3.3 KiB
Безопасность и экранирование
Главная защита от SQL-инъекций — плейсхолдеры. Ручное экранирование нужно лишь в редких случаях (динамический SQL, который нельзя выразить плейсхолдером).
Правило №1 — плейсхолдеры
// ХОРОШО — значение экранируется QueryBuilder
DB::query('SELECT * FROM p WHERE title = %s AND rubric_id = %i', $title, $rid);
// ОПАСНО — прямая склейка пользовательского ввода
DB::query("SELECT * FROM p WHERE title = '$title'"); // ← SQL-инъекция
Полный список плейсхолдеров — placeholders.md.
Ручное экранирование (когда без него никак)
| Метод | Что делает |
|---|---|
DB::escape($value) |
Экранировать строку (без кавычек). |
DB::quote($value) |
Экранировать и обернуть в кавычки. |
DB::safe($value) |
Безопасное приведение значения. |
$name = DB::quote($userInput); // 'экранированное_значение'
DB::query('... WHERE name = ' . $name);
Если можно выразить через
%s/%i/%li— делайте это, а не ручнойquote.
Имена таблиц и полей
Идентификаторы (имена таблиц/колонок) нельзя параметризовать как значения —
для них есть %b / %lb (оборачивают в обратные кавычки) и
резолверы имён таблиц.
DB::query('SELECT * FROM %b WHERE %b = %i', $table, $column, $id);
Если имя поля приходит извне (например, «искать по выбранному полю») — сверяйте с
белым списком допустимых полей перед подстановкой, даже с %b.
$allowed = array('title', 'article', 'alias');
if (!in_array($field, $allowed, true)) { $field = 'title'; }
DB::query('SELECT * FROM p WHERE %b LIKE %ss', $field, $q);
%l — сырое значение
%l вставляет значение как есть, без экранирования. Используйте только для
доверенных, программно сформированных фрагментов (например, заранее собранных
условий), никогда — для пользовательского ввода.
Чек-лист
- Все значения — через плейсхолдеры (
%i,%s,%ss,%li, …). - Имена таблиц — через резолверы; имена полей — через
%b+ whitelist. - Никакой конкатенации
$_GET/$_POSTв строку SQL. %l/safe— только для доверенных данных.- На запись, меняющую состояние (POST) — проверка CSRF на уровне контроллера.