Коды представлений, хранимых процедур, функций и триггеров являются системной информацией, и по умолчанию сохраняются в системных таблицах незашифрованными. Пользователь, имеющий право на чтение этих таблиц, имеет возможность просматривать коды интересующих его программных объектов БД. Если код программного объекта по каким-либо причинам необходимо скрыть, то при его создании следует воспользоваться опцией 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. Выполняется конкатенация статической и динамической частей запроса. Именно в этом и заключается основная ошибка разработчика.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.