Что должен доказать тестировщик, чтобы считать параметр защищённым от SQL-инъекции?
Тестировщик должен подтвердить, что пользовательское значение передаётся в базу данных как отдельный параметр, а не объединяется со структурой SQL-запроса. Одного экранирования кавычек или отсутствия очевидной ошибки недостаточно: нужно проверить поведение приложения на специальных значениях и, по возможности, реализацию формирования запроса.
SQL-инъекции возникали из-за смешивания кода запроса и данных пользователя. Когда приложение строило SQL конкатенацией строк, специально сформированное значение могло изменить условие, добавить оператор или повлиять на выполняемую команду.
Подход с параметризованными запросами появился как способ разделить эти две сущности: структура запроса компилируется отдельно, а пользовательское значение передаётся базе данных как данные. Это снижает риск изменения смысла запроса через содержимое параметра.
Уязвимость может присутствовать в поиске, фильтрации, авторизации, сортировке или любом другом месте, где пользовательский ввод участвует в запросе к базе данных. Последствия включают обход проверки доступа, чтение чужих данных, изменение или удаление записей, а в некоторых конфигурациях — дальнейшее воздействие на сервер базы данных.
Проверка только обычных значений не доказывает безопасность. Важно установить, что специальные символы и последовательности не превращаются в часть SQL-структуры, а обрабатываются как буквальное значение или отклоняются валидатором.
Основной критерий — разделение структуры и данных. При параметризации база данных получает шаблон запроса с маркером параметра и отдельное значение; кавычки, пробелы, операторы и другие символы внутри значения не меняют структуру шаблона.
Концептуально взаимодействие выглядит так:
Тестировщик должен проверить несколько аспектов:
Надёжным подтверждением является анализ реализации или трассировки, где видно использование параметров, а не конкатенацию строк. Поведенческий тест полезен, но не абсолютен: конкретный тестовый набор может не покрыть все места формирования запросов.
Параметры обычно защищают значения, но не произвольные имена таблиц, столбцов или направление сортировки. Для таких частей применяют жёсткий список допустимых вариантов, сопоставление внешних значений с внутренними идентификаторами и отдельную проверку авторизации.
Экранирование может быть дополнительной мерой, но не универсальной заменой параметризации: его корректность зависит от контекста, кодировки, драйвера и режима SQL. Кроме того, разные участки приложения могут использовать разные соединения или библиотеки и иметь неодинаковое поведение.
В функции поиска приложение корректно параметризовало поисковую строку, но сортировка принимала имя столбца из запроса пользователя. Первоначальный вариант — пропускать это имя через экранирование. Его преимущество — простая интеграция, но оно не превращает идентификатор столбца в безопасное значение и может быть неверным для конкретного диалекта базы данных.
Второй вариант — разрешать только значения из заранее определённого списка и преобразовывать их во внутренние имена столбцов. Он требует поддержки списка при изменении схемы, зато исключает передачу произвольной структуры запроса от пользователя.
Был выбран второй вариант, а значения фильтров оставили параметризованными. Повторная проверка подтвердила, что специальные значения в фильтрах не меняют результат запроса, а неизвестные варианты сортировки отклоняются ещё до обращения к базе данных.
1. Достаточно ли проверить, что приложение не показывает ошибку базы данных?
Нет. Отсутствие ошибки не доказывает отсутствие SQL-инъекции: приложение может подавлять исключения, возвращать одинаковый ответ или уязвимость может проявляться только в другом запросе. Нужно проверять изменение результата, побочные эффекты и, когда возможно, фактический способ передачи параметров.
2. Можно ли параметризовать имя столбца или направление сортировки так же, как значение фильтра?
Обычно параметр предназначен для значения, а не для структурного идентификатора SQL. Имя столбца и направление сортировки выбирают через жёсткий список допустимых вариантов, после чего в запрос попадает только заранее заданный фрагмент. Передача таких элементов напрямую из пользовательского ввода создаёт отдельный риск даже при параметризации значений фильтра.
3. Достаточно ли параметризовать запрос только в основном обработчике?
Нет. Уязвимость может находиться в отчёте, административной функции, фоновой задаче, процедуре импорта или библиотечном модуле. Проверка должна охватывать все места, где пользовательские данные достигают базы данных, включая вторичные параметры, скрытые поля и значения, сохранённые ранее в хранилище.