Риски безопасности
Базы данных часто содержат конфиденциальные данные и позволяют выполнять опасные операции. Для безопасной работы с Nette Database ключевыми аспектами являются:
- Понимание разницы между безопасным и небезопасным API
- Использование параметризованных запросов
- Правильная валидация входных данных
Что такое SQL-инъекция?
SQL-инъекция – это самый серьезный риск безопасности при работе с базами данных. Она возникает, когда нефильтрованный пользовательский ввод становится частью SQL-запроса. Злоумышленник может вставить свои собственные SQL-команды и тем самым:
- Извлечь несанкционированные данные
- Изменить или удалить данные в базе данных
- обойти аутентификацию
То же самое относится и к Database Explorer:
Безопасные параметризованные запросы
Фундаментальной защитой от SQL-инъекций являются параметризованные запросы. Nette Database предоставляет несколько способов их использования.
Самый простой способ – использовать знаки вопроса:
Это относится ко всем остальным методам в Database Explorer, которые позволяют вставлять выражения с вопросительными знаками и параметрами.
В пунктах INSERT
, UPDATE
или WHERE
можно передавать
значения в виде массива:
Проверка значений параметров
Параметризованные запросы – краеугольный камень безопасной работы с базами данных. Однако передаваемые в них значения должны проходить несколько уровней проверки:
Проверка типа
Убедиться в правильности типа данных параметров очень важно – это необходимое условие для безопасного использования Nette Database. База данных предполагает, что все входные данные имеют правильный тип данных, соответствующий столбцу.
Например, если бы $name
в предыдущих примерах неожиданно стал не
строкой, а массивом, Nette Database попыталась бы вставить в SQL-запрос все его
элементы, что привело бы к ошибке. Поэтому никогда не используйте
невалидированные данные из $_GET
, $_POST
или $_COOKIE
непосредственно в запросах к базе данных.
Валидация формата
На втором уровне проверяется формат данных – например, убедитесь, что строки закодированы в UTF-8 и их длина соответствует определению столбца, или проверьте, что числовые значения попадают в допустимый диапазон для типа данных столбца.
На этом уровне вы можете частично положиться на саму базу данных – многие базы данных отвергают недопустимые данные. Однако поведение может быть разным: некоторые из них могут обрезать длинные строки без звука или обрезать числа, выходящие за пределы диапазона.
Проверка с учетом специфики домена
Третий уровень включает в себя логические проверки, специфичные для вашего приложения. Например, проверка соответствия значений из полей выбора имеющимся вариантам, попадания чисел в ожидаемый диапазон (например, возраст 0–150 лет) или взаимосвязи между значениями.
Рекомендуемые методы валидации
- Используйте формы Nette Forms, которые автоматически выполняют проверку всех вводимых данных.
- Используйте презентеры и объявляйте типы
данных параметров в методах
action*()
иrender*()
. - Или реализуйте собственный слой валидации с помощью стандартных
средств PHP, таких как
filter_var()
.
Безопасная работа с колонками
В предыдущем разделе мы рассказали о том, как правильно проверять значения параметров. Однако при использовании массивов в SQL-запросах необходимо уделять не меньшее внимание их ключам.
Для команд INSERT и UPDATE это серьезный недостаток безопасности –
злоумышленник может вставить или изменить любой столбец в базе данных.
Например, они могут установить is_admin = 1
или вставить
произвольные данные в чувствительные столбцы (известная как
уязвимость массового назначения).
В условиях WHERE это еще опаснее, поскольку они могут содержать операторы:
Злоумышленник может использовать этот подход для систематического выявления зарплат сотрудников. Они могут начать с запроса о зарплатах выше 100 000, затем ниже 50 000 и, постепенно сужая диапазон, выявить приблизительные зарплаты всех сотрудников. Такой тип атаки называется SQL-перечислением.
Методы where()
и whereOr()
еще более гибкие
и поддерживают SQL-выражения, включая операторы и функции, как в ключах,
так и в значениях. Это дает злоумышленнику возможность выполнять
сложные SQL-инъекции:
Эта атака завершает исходное условие с помощью 0)
, добавляет
свой собственный SELECT
с помощью UNION
для получения
конфиденциальных данных из таблицы users
и завершается
синтаксически корректным запросом с помощью WHERE (1)
.
Белый список столбцов
Для безопасной работы с именами столбцов необходим механизм, который гарантирует, что пользователи смогут взаимодействовать только с разрешенными столбцами и не смогут добавлять свои собственные. Попытка обнаружить и заблокировать опасные имена столбцов (черный список) ненадежна – злоумышленник всегда может придумать новый способ написать опасное имя столбца, который вы не предусмотрели.
Поэтому гораздо безопаснее изменить логику и определить явный список разрешенных колонок (белый список):
Динамические идентификаторы
Для динамических имен таблиц и столбцов используйте заполнитель
?name
. Это обеспечит правильное экранирование идентификаторов в
соответствии с синтаксисом данной базы данных (например,
использование обратных знаков в MySQL):
Важно: Используйте символ ?name
только для доверенных значений,
определенных в коде приложения. Для значений, предоставленных
пользователем, снова используйте белый список. В
противном случае вы рискуете получить уязвимости в системе
безопасности: