Введение в дисциплину «Безопасность систем баз данных». Теоретические основы построения реляционных баз данных. Верификация баз данных и проведение аудита в СБД. Распределенные базы данных, страница 58

Коды представлений, хранимых процедур, функций и триггеров являются системной информацией, и по умолчанию сохраняются в системных таблицах незашифрованными. Пользователь, имеющий право на чтение этих таблиц, имеет возможность просматривать коды интересующих его программных объектов БД. Если код программного объекта по каким-либо причинам необходимо скрыть, то при его создании следует воспользоваться опцией WITH ENCRYPTION. Данная опция может быть указана в командах CREATE VIEW, CREATE PROCEDURE, CREATE FUNCTION, CREATE TRIGGER. Зашифрованные программные объекты остаются доступными для рекомпиляции.

6.3. Защита баз данных от «внедрения в SQL»

Разработчики программного обеспечения имеют возможность создавать собственные клиентские программы для работы с БД. Для этого в современных языках программирования имеются специальные средства (API-функции, библиотеки компонентов), позволяющие клиентским программам:

·  устанавливать соединение с сервером и БД, используя учетные записи;

·  отправлять на сервер SQL-запросы, получать и обрабатывать результаты выполнения запросов.

Атака «внедрение в SQL», называемая также SQL-инъекцией (от англ. SQL-injection) – весьма распространенный способ взлома БД и серверов СУБД через клиентские программные приложения. Несмотря на то, что библиотеки большинства современных систем программирования содержат эффективные средства предупреждения SQL-инъекций, многие приложения остаются уязвимыми просто потому, что разработчики не знакомы с вопросами безопасности СБД и не знают об опасностях SQL-инъекций.

Рассмотрим в качестве примера небольшое приложение Registrator, работающее с одноименной БД на SQL Server. На рис. 6.1 показано окно приложения с активной вкладкой «Запросы». Здесь, очевидно, выполняется поиск информации. Пользователю нужно выбрать тип интересующего запроса и, если требуется, ввести параметр поиска. Для запроса «Кафедры заданного факультета» нужно ввести параметр – полное название факультета (например, «Электротехнический»). Сам поиск инициируется нажатием на кнопку «Старт», а результатом поиска будет список кафедр, зарегистрированных в БД и относящихся к электротехническому факультету вуза.

Рисунок 6.1 – Приложение Registrator

Обратимся к реализации данного приложения. Формирование запроса и его выполнение происходят в обработчике события от кнопки Старт. Ниже представлен его фрагмент. Предварительно заметим, что в нем фигурируют следующие программные объекты:

QueryDataSet – отвечает за формирование и выполнение SQL-запросов, а также за обработку их результатов, т. е. реализует все этапы работы с курсором;

QueryEdit – текстовое поле для ввода, расположенное на закладке Запросы.

void __fastcall TMainForm::QueryGoBtnClick(TObject *Sender)

{

        //Закрыть набор, если он открыт

        if(QueryDataSet->Active)

                QueryDataSet->Close();

        //QueryCB->ItemIndex содержит номер выбранного элемента списка

        //В зависимости от его значения составляется SQL-запрос

        switch(QueryCB->ItemIndex)

        {

        case 0:

                QueryDataSet->CommandText = "select fac_name as Название, abbreviation as Аббревиатура from faculties";

                break;

        case 1:

                QueryDataSet->CommandText = "select ch_name as Название from faculties_chairs where fac_name = '" + QueryEdit->Text + "'";

                break;

               ………………………………….

        default:

                ShowMessage("Ничего не выбрано!");

        }

        //Нужный запрос определен - выполнить его

        QueryDataSet->Open();

}

Очевидно, что запрос формируется в зависимости от того, какой (по счету) элемент выпадающего списка является текущим. Индекс элемента «Кафедры заданного факультета» равен единице. Следовательно, в операторе switch будет сформирован запрос из секции case 1. Он формируется на основе статического текста и содержимого текстового поля, хранящегося в переменной QueryEdit->Text. Выполняется конкатенация статической и динамической частей запроса. Именно в этом и заключается основная ошибка разработчика.