Услуги Создание магазина Доработка Интеграция 1С О компании FAQ Блог Кейсы Отзывы Контакты
А
Автор статьи

Как писать безопасный SQL в модулях OpenCart

SQL-инъекция — уязвимость, при которой злоумышленник может выполнить произвольный SQL-запрос к базе данных. В OpenCart, где многие модули пишут разработчики разного уровня, это одна из самых частых проблем безопасности. Одна неправильная строка в модуле — и вся база данных открыта для взлома.

Из практики: правильная архитектура модуля экономит дни поддержки.

В этой статье — четыре правила безопасного SQL в OpenCart, типовые ошибки и как их избежать.

Правило 1. Всегда экранируйте строки

Если вы подставляете пользовательские данные (название товара, имя покупателя, комментарий) в SQL-запрос — используйте $this->db->escape($value):

// Неправильно — SQL-инъекция!
$name = $this->request->post['name'];
$this->db->query("SELECT * FROM " . DB_PREFIX . "product WHERE name = '$name'");

// Правильно — данные экранированы
$name = $this->db->escape($this->request->post['name']);
$this->db->query("SELECT * FROM " . DB_PREFIX . "product WHERE name = '$name'");

Что делает escape(): экранирует кавычки и специальные символы, которые могут быть использованы для SQL-инъекции.

Правило 2. Приводите числа к int

Для числовых параметров (ID товара, количество, цена) используйте приведение типа — это проще и надёжнее экранирования:

// Правильно — число приведено к int
$product_id = (int)$this->request->get['product_id'];
$this->db->query("SELECT * FROM " . DB_PREFIX . "product WHERE product_id = $product_id");

// Неправильно — строка подставляется без приведения
$product_id = $this->request->get['product_id'];
$this->db->query("SELECT * FROM " . DB_PREFIX . "product WHERE product_id = $product_id");

Правило 3. Не конкатенируйте имена таблиц и колонок

Имя таблицы или колонки не должно приходить из пользовательского ввода. Если нужно динамическое имя — используйте белый список:

// Неправильно — SQL-инъекция через имя колонки
$column = $this->request->get['sort'];
$this->db->query("SELECT * FROM " . DB_PREFIX . "product ORDER BY $column");

// Правильно — белый список допустимых значений
$allowed = ['name', 'price', 'date_added', 'model'];
$column = in_array($this->request->get['sort'], $allowed) ? $this->request->get['sort'] : 'name';
$this->db->query("SELECT * FROM " . DB_PREFIX . "product ORDER BY $column");

Правило 4. Всегда используйте DB_PREFIX

В OpenCart таблицы имеют префикс (например, oc_product). Всегда используйте константу DB_PREFIX:

// Правильно
$this->db->query("SELECT * FROM " . DB_PREFIX . "product WHERE product_id = $product_id");

// Неправильно — будет работать только с префиксом oc_
$this->db->query("SELECT * FROM oc_product WHERE product_id = $product_id");

Типовые ошибки

Ошибка Пример Решение
Пропущен escape() WHERE name = '$name' Используйте $this->db->escape()
LIKE без экранирования WHERE name LIKE '%$search%' Экранируйте % и _ отдельно
Число не приведено к int WHERE id = $id Используйте (int)$id
Имя колонки из ввода ORDER BY $column Белый список допустимых значений
Нет DB_PREFIX FROM product Используйте DB_PREFIX . 'product'

Как проверить модуль на SQL-инъекции

  1. Найдите все вызовы $this->db->query() в коде модуля.
  2. Проверьте каждый запрос: все ли переменные экранированы?
  3. Проверьте числовые параметры: приведены ли к int?
  4. Проверьте имена таблиц/колонок: не приходят ли из пользовательского ввода?
  5. Проверьте LIKE-запросы: экранированы ли спецсимволы?

Чек-лист безопасности

  • Все строковые параметры экранированы через $this->db->escape()
  • Все числовые параметры приведены к (int)
  • Имена таблиц/колонок не приходят из пользовательского ввода
  • Все запросы используют DB_PREFIX
  • LIKE-запросы экранируют % и _
  • Нет динамического построения SQL без белого списка

Рекомендации из практики

Как лучше: Всегда используйте (int) для числовых параметров из URL — это самый простой и надёжный способ защиты. ID товара, ID категории, лимит, страница — любые числа должны проходить через (int). По практике, большинства SQL-инъекций в OpenCart-модулях происходят именно через незащищённые числовые параметры.

Как не делать: Не экранируйте числа через escape() — это избыточно. Для чисел достаточно (int), для строк — escape. Смешение подходов — частая ошибка новичков.

Кейс из практики: Аудит OpenCart-магазина показал, что в кастомном модуле фильтров SQL-запрос собирался через конкатенацию. Через параметр cat=1 UNION SELECT можно было вытянуть базу пользователей. Исправили за несколько минут: добавили (int) к параметру.

Нужен аудит безопасности — закажите технический аудит: проверим SQL-запросы и модули на уязвимости.

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

OpenCart уже защищает от SQL-инъекций?

Частично. Метод $this->db->escape() экранирует строки, но не защищает от ошибок разработчика. Если разработчик забыл вызвать escape() или неправильно привёл число — уязвимость остаётся. Проверка модулей — ответственность разработчика.

Как быстро проверить модуль на SQL-инъекции?

Найдите все вызовы $this->db->query() (grep по коду модуля) и проверьте каждый запрос по чек-листу выше. Обычно это 10–20 запросов в модуле — проверка занимает 15–30 минут.

Что делать, если нашёл SQL-инъекцию в модуле?

Если модуль поддерживается — сообщите автору. Если модуль не поддерживается — исправьте самостоятельно (или попросите разработчика) по правилам выше. Не используйте модуль с известной уязвимостью — это риск для всего сайта.

Как проверить все модули на SQL-инъекции разом?

Используйте grep по папке модулей. Все найденные места, где GET-параметр попадает в SQL-запрос без (int) или escape — потенциальная уязвимость. По практике, этой проверкой закрывается большинство проблем безопасности.

Связанные темы

Безопасный SQL — это не опция, а обязательное требование для каждого модуля. Если нужно проверить модуль на уязвимости или написать безопасный код — доработка OpenCart это наш профиль.

← Предыдущая Как обновлять OpenCart-модули без поломки сайта Следующая → Как не сломать OpenCart при доработке чужого модуля

Комментарии (0)

Пока нет комментариев. Будьте первым!

Оставить комментарий

Ваш комментарий появится после проверки модератором.