В языке sql существует множество способов объединения или, иначе говоря, конкатенации строк. Для данной операции как правило используют строковые функции или специальные синтаксические конструкции (рис. 1 – 3).
В качестве альтернативы, предлагается перейти к системе обращения с базой данных посредством хранимых процедур и определяемых пользователем функций. В теле вышеприведенных системных объектов в таком случае будет располагаться sql-запрос, в который будут передаваться введенные пользователем данные в качестве параметров.
Данный подход избавлен от минусов системы защиты от sql-инъекций посредством подготовленных выражений.
Во первых, увеличивается скорость обработки запросов и скорость работы с базой данных в целом. Обработка каждой инструкций sql в основном состоит из пяти последовательных шагов.
Чтобы обработать инструкцию SQL, СУБД выполняет следующие пять шагов:
- СУБД сначала анализирует инструкцию SQL. Она разбивает оператор на отдельные слова, называемые токенами, и гарантирует, что оператор имеет допустимый синтаксис и допустимые предложения, и т. д. На этом шаге могут быть обнаружены синтаксические ошибки и опечатки.
- СУБД проверяет инструкцию. Далее проходит проверка по по системному каталогу. Существуют ли в базе данных все таблицы и прочие объекты, на которые происходят ссылки внутри инструкции. Существуют ли все столбцы, и являются ли имена столбцов однозначными. Происходит проверка прав и привилегий у пользователя, необходимых для выполнения инструкции. На этом шаге могут быть обнаружены некоторые семантические ошибки.
- СУБД создает план запроса для инструкции. План запроса – это двоичное представление шагов, необходимых для выполнения инструкции. Иначе говоря эквивалент исполняемого кода СУБД.
- СУБД оптимизирует план запроса. В нем рассматриваются различные способы выполнения плана запроса. Можно ли использовать индекс для ускорения поиска. Следует ли СУБД сначала применить условие поиска к таблице A, а затем присоединить ее к таблице B или начать с объединения и использовать условие поиска позже. Можно ли избежать последовательного поиска в таблице до подмножества таблицы. После изучения альтернативы СУБД выбирает один из них.
- СУБД выполняет инструкцию, запустив план запроса (рис. 4).
При использовании хранимых процедур и функций для обращения с базой, несколько этапов обработки sql-запроса пропускаются. По умолчанию компиляция процедуры и создание плана выполнения, используемого для последующих выполнений, производится при ее первом запуске Поскольку обработчику запросов не нужно создавать новый план, обычно обработка процедуры занимает меньше времени.
Во вторых, если клиентские приложения вызывают процедуры, а операции баз данных остаются на уровне данных, то для внесения изменений в основную базу данных будет достаточно обновить только процедуры. Уровень приложения остается незатронутым изменениями в схемах баз данных, связях или процессах.
В третьих, если какой-то код многократно используется в операции базы данных, то отличным решением будет произвести его инкапсуляцию в процедуры. Это устранит необходимость излишнего копирования того же кода, снизит уровень несогласованности кода и позволит осуществлять доступ к коду любым пользователям или приложениям, имеющим необходимые разрешения.
В четвертых, использование процедур и функций делают общение базы данных и клиентского приложения более безопасным. Использование параметров в процедурах помогает предотвратить атаки типа «инъекция SQL». Поскольку входные данные параметра обрабатываются как литеральные значения, а не как исполняемый код, злоумышленнику будет труднее вставить команду в инструкции Transact-SQL в процедуре и создать угрозу безопасности. Так же при вызове процедуры через сеть виден только вызов на выполнение процедуры. Следовательно, злоумышленники не смогут видеть имена объектов таблиц и баз данных, внедрять свои инструкции Transact-SQL или выполнять поиск важных данных.
Ускорение так же достигается за счет того, что команды в процедурах и функциях выполняются как один пакет кода. Это позволяет существенно сократить сетевой трафик между сервером и клиентом, поскольку по сети отправляется только вызов на выполнение процедуры. Без инкапсуляции кода, предоставляемой процедурой, по сети бы пришлось пересылать все отдельные строки кода.
Таким образом, для защиты базы данных от sql-инъекций при общении с клиентским приложением верхнего уровня, на концептуальном уровне необходимо:
- Для запросов на поиск и выдачу информации типа «select» использовать определяемые пользователем функции.
- Для запросов «insert», «update», «delete» использовать хранимые процедуры с параметрами.
- Для особо сложных случаев, где необходима дополнительная логика в запросах, и необходим динамический sql – использовать механизм защиты, разработанный в ходе данного исследования.
Список литературы
- Марков А. С., Миронов С. В., Цирлов В. Л. Выявление уязвимостей в программном коде // Открытые системы. 2005, № 12.
- Егоров М. Выявление и эксплуатация sql-инъекций в приложениях. Защита информации. // INSIDE № 2’2011.
- Сайт «MSDN» [Электронный ресурс] – Режим доступа https://docs.microsoft.com/ru-ru/sql/relational-databases/security/sql-injection?view=sql-server-ver15, свободный. Дата обращения 10.03.2021 г.