Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР 124, АПРЕЛЬ 2009 г.

Базу данных не стащить! Правильные способы защитить данные в таблицах БД

Андрей Комаров (komarov@itdefence.ru)




Как же ошибаются те люди, которые доверяют защиту данных исключительно самой СУБД. Мол, если пароль на подключение хороший и версия демона – самая последняя, то все будет нормально. Ничего подобного. Базы как сливали, так и будут сливать. А наша задача – сделать их нечитаемыми для тех, кому они не предназначены.

Актуальная проблема из мира информационной безопасности – обеспечить сохранность данных. Есть ситуации, в которых даже при наличии серьезной защиты системы, сохранность данных оказывается под большим вопросом. Как так? Могу привести пример из личного опыта, когда в разглашении информации был виновен засланный сотрудник конкурирующей компании. Находясь на рабочем местом и будучи технически подкованным, он взламывал сервера баз данных банальным брутфорсом через терминальное соединение. Базы с клиентами «засланец» перепродавал другим компаниям, а «интересная» информация о ведении бизнеса отправлялась сотрудникам силовых структур. Что из этого вышло, объяснять излишне.

Вообще, имея физический доступ к локальной сети, инсайдер мог поступить гораздо проще: атаковать программу, которая работает с базой данных. Нередко сценарий взлома сводится к тому, что из программы разными способами извлекаются конфиги для подключения к базе. Захватив ту же 1С, которая хранит в себе конфиги подключения к базе (в том числе, шифрованный обычным XOR'ом пароль), злоумышленник получает доступ к самой базе. Особо не стесняясь, он может ее выкачать, модифицировать или просто удалить. Такая брешь в защите способна сыграть злую шутку, особенно в корпоративной среде.

В статье я как раз хочу рассказать о том, как обезопасить информацию в обычной базе данных. Даже если СУБД будет взломана или левый человек скопирует данные, утечки конфиденциальной информации не произойдет!

Шифрованию – быть!

Общий подход прост до гениального: раз злоумышленник гипотетически сможет извлечь данные, надо сделать так, чтобы он их не смог прочитать. Информацию все равно придется хранить в базе, но… ничего не мешает хранить ее в каком угодно виде, в том числе зашифрованном! Главное, чтобы мы сами потом смогли расшифровать :).

Компания Spelabs (spellabs.ru/spellabsCrypto1C.htm) как-то анонсировала продукт, организующий дополнительную безопасность бухгалтерских 1С на уровне шифрования данных, причем на полностью прозрачном уровне. Пользовательские приложения, не подозревая о надстройке, работали в обычном режиме. Увы, компания прекратила разработку этого направления. Но реально обойтись и без подобных инструментов, ведь для шифрования сгодятся даже штатные средства СУБД!

Любая современная СУБД, если это, конечно, не собранная на коленке курсовая, может похвастаться достаточно надежными механизмами шифрования данных. В той же самой MySQL я по памяти насчитал около 14 соответствующих функций, которые тебе наверняка хорошо известны:

  • AES_ENCRYPT() Шифрование AES
  • AES_DECRYPT() Расшифровка AES
  • COMPRESS() Возвращение результата в бинарном виде
  • DES_ENCRYPT() Шифрование DES
  • DES_DECRYPT() Дешифрование DES
  • ENCODE() Шифрование строки поверхностным паролем (на выходе получается шифрованное слово первоначальной «plaintext» длины
  • DECODE() Расшифровка текста, обработанного функцией ENCODE()
  • ENCRYPT() Шифрование с помощью Unix’ового системного вызова crypt
  • MD5() Подсчет MD-5 суммы
  • SHA1(), SHA() Подсчет SHA-1 (160-бит)

Для их применения надо лишь чуть изменить свои SQL-запросы, добавив в нужном месте функции AES_ENCRYPT() или DES_ENCRYPT(), которые считаются наиболее надежными в MySQL на текущий момент. Например, так:

INSERT INTO t VALUES (1,AES_ENCRYPT('text','password'));

Приятно признать, что хорошие программисты эти функции используют. Часто во время проведения SQL-инжекции мне приходилось ломать голову и определять функцию, которую использовал кодер для крипточки данных. В результате, требуется производить те же AES_DECRYPT(AES_ENCRYPT()) наряду с unhex(hex()).

T-SQL

Помимо симметричного шифрования, когда упаковка и распаковка текста производятся одним и тем же ключом (общим для двух участников обмена сообщениями), поддерживается и ассиметричное криптование. Идея ассиметричных алгоритмов подразумевает наличие двух ключей – открытого и закрытого (секретного). Один из них используется для шифрования информации, а другой — для дешифрования. Если кодирование осуществляется с помощью открытого ключа, то расшифровать такие данные можно только с помощью парного ему закрытого. Предлагаю разобратьсяс этим на примере Microsoft SQL Server, который часто используется в корпоративных порталах и сложных приложениях.

Для шифрования применяются функции T-SQL, представляющие собой специальное дополнение языка SQL. Оно поддерживает управляющие операторы, локальные переменные и различные дополнительные функции.

Одна из таких функций - EncryptByCert(), используемая для ассиметричного шифрования данных с помощью сертификатов. Открытым ключом тут выступает сертификат. Только откуда этот сертификат взять? Ответ прост – сгенерировать с помощью другой специальной функции. Покажу на примере, как можно сгенерировать сертификат с именем для andrej базы «Bank» с помощью хранимой процедуры:

USE Bank;
CREATE CERTIFICATE andrej
ENCRYPTION BY PASSWORD = 'pGFD4bb925DGvbd2439587y'
# Для генерации с использованием подгрузки из файла
# FROM FILE = 'c:\Shipping\Certs\Shipping11.cer'
# WITH PRIVATE KEY (FILE = 'c:\Shipping\Certs\Shipping11.pvk',
WITH SUBJECT = 'Employers Access',
EXPIRY_DATE = '10/31/2009';
GO

У нас создался сертификат! Теперь его можно без проблем использовать для размещения в таблице зашифрованных записей, выполняя привычные SQL-запросы:

INSERT INTO [БАЗА].[ТАБЛИЦА]
values( N'ДАННЫЕ ДЛЯ ЗАШИФРОВКИ’,
EncryptByCert(Cert_ID('andrej'), @cleartext) );
GO

В этом примере неформатированный текст из переменной @cleartext шифруется сертификатом с именем «andrej». Зашифрованные данные помещаются в таблицу «ТАБЛИЦА». Уточню, что данные могут быть расшифрованы только с помощью соответствующего закрытого ключа (как уже было сказано, «приватного»).
Имя функции для обратного преобразования угадать несложно: DecryptByCert(). А вот синтаксис более хитер, и с ним все чуть сложнее. Дело в том, что на приватный ключ, как правило, закладывается дополнительный пароль (passphrase). Его необходимо ввести, и по этой причине он обязательно будет присутствовать в коде запроса или процедуры. Это не очень хорошо, потому что в этом случае его можно быстро увести. Но с этим мы разберемся позже, когда поговорим о безопасности хранимых процедур. А пока – код для извлечения данных из шифрованной базы данных:

SELECT convert(nvarchar(max), DecryptByCert(Cert_Id('andrej'),
ProtectedData, N'pGFD4bb925DGvbd2439587y'))
FROM [БАЗА].[ТАБЛИЦА]
WHERE Description
= N'Employers Access’;
GO

В этом примере производится выборка строк из таблицы [БАЗА].[ТАБЛИЦА], помеченных как «Employers Access». Пример дешифрует зашифрованный текст с помощью закрытого ключа сертификата «Andrej» и дополнительного пароля pGFD4bb925DGvbd2439587y. Расшифрованные данные преобразуются из типа varbinary в тип nvarchar.

Надо сказать, что ассиметричные преобразования гораздо более накладны, чем шифрование и дешифрование с использованием симметричного ключа. Поэтому использование ассиметричного шифрования не рекомендуется при работе с большими объемами данных, например, таблицами пользовательских данных. Это важно учитывать при особо больших базах, а также базах, структура которых не приведена к одной из нормальных форм.

Прячем хранимые процедуры!

Если ты не заметил, многое упирается в то, что вся конфиденциальность и целостность завязана на использование хранимых процедур или функций. Получается, что, получив к ним доступ и грамотно проанализировав их код, любой опытный хакер сможет преобразовать шифрованную белиберду в исходный текст. Конечно, добраться до кода процедур далеко не всегда реально, потому здесь всплывает вопрос об утечке программной начинки производства, а именно – логике ПО. Но именно по этой причине необходимо прибегать к шифрованию процедур и функций в базе. Одно из самых популярных и удачных средств для таких действий – это программа SQL Shield (www.sql-shield.com). После несложной установки приложения не забудь указывать дополнительный флаг /*sqlshield*/ с выражением «WITH ENCRYPTION» всякий раз, когда будешь создавать защищенную процедуру. Вот пример функции, которая исполняет простейший запрос к базе:

CREATE PROCEDURE MyTest
WITH /*sqlshield*/ ENCRYPTION
AS
SELECT 2+2

Исполняем процедуру и получаем:

MyTest
> 4

Проверим, в каком виде хранится процедура, с помощью специального средства для ковыряния в файлах базы. Подойдет SQL Server Syscomments Decryptor (www.geocities.com/d0mn4r/dSQLSRVD.html), который при отображении текста процедуры показывает одни лишь знаки вопроса.
Все работает!

Как облегчить себе жизнь?

В заключение – не менее интересный продукт XP_CRYPT (xpcrypt.com). Это средство осуществляет весь тот геморрой, который мы только что проделали вручную. Все, что от тебя требуется, – скачать дистрибутив проги, установить ее на сервер (к сожалению, есть версия только для Винды), обозначить свою базу данных и начать химию с таблицами с помощью удобного GUI-интерфейса.

Организуем знакомство на примере из практики. Предположим, у нас есть интернет-магазин, где каким-то образом хранятся данные о кредитных картах клиентов (распространенная ситуация, хотя это категорически запрещено!). Наша задача - зашифровать конкретные данные о клиентах, т.е. поля с паролем, номером кредитной карточки и т.п. Пока мы ничего не делали, при запросе SELECT * FROM tbl_CCards, СУБД возвращает все в открытом виде:

UsernamePassword CredCardNum
jamesgod1234567890123456
lucassex2894787650102827
annalove3234563638716434

Напишем внешнюю функцию UDF (расшифровывается, как «User-Defined-Function», подробности – в последнем выпуске «Обзора эксплоитов») для преобразования строки в SHA-хеш:

CREATE FUNCTION ud_MakeSHA1 (@clearpass VARCHAR (8000) )
RETURNS VARCHAR (40)
AS
BEGIN
DECLARE @ret as VARCHAR(40)
EXEC master..xp_sha1 @clearpass,@ret OUTPUT
RETURN @ret
END

Отдаем команду: UPDATE tbl_CCards SET password = dbo.ud_MakeSHA1(Password). После чего еще раз проверяем содержимое базы той же командой. Что видим? Все зашифровано, все пароли захешировались!

Теперь нужно не забыть о том, что мы используем шифрование при обращении к базе. В нашем случае, когда ты будешь делать авторизацию пользователей, процедура проверки пароля по хешу будет выглядеть примерно так:

CREATE FUNCTION ud_CheckUser (@username VARCHAR(16),@clear_pass VARCHAR (16))
RETURNS INTEGER
AS BEGIN
DECLARE @res INTEGER
SELECT @res = count(*) FROM tbl_CCards where username=@username AND password=dbo.ud_MakeSHA1(@clear_pass)
IF @res > 1 SELECT @res= 0
RETURN @res
END

Проверяем исполнением команды:

SELECT dbo.ud_CheckUser ('anna','kolbaska')
>1 (неправильно)
SELECT dbo.ud_CheckUser ('anna','love')
>0 (окейно!)

К шифрованию номера кредитной карты надо подойти более серьезно. Впрочем, мы не будем вникать в различного рода стандарты по информационной безопасности в платежно-карточной сфере (вроде PCI; хотя организации, работающие с кредитными картами, безусловно обязаны это делать). В бесплатной версии XP_CRYPT существует возможность генерации только 256-битного ключа RSA. Вот этим и можно воспользоваться (пусть упомянутый стандарт и требует, как минимум, 768-битного ключа). Я бы мог сейчас привести код по генерации публичного и приватного ключа, но… поступим проще. Все действия можно выполнить из понятного графического интерфейса, и во многих случаях оставить все на совести программы, не написав ни строчки кода. И поверь, будет работать!

Пример из личного опыта

Сотрудниками одной из компаний платежно-карточного сектора велась база данных для выдачи зарплат. Для простого понимания, – пусть это будет примерно следующая структура:

IDLastNameFirstNameEmpSum
354SomovOlegIT-ManagerM0x8900f56543
643AntipovaAlexandraDirector4343Lax#dsdsss
411TimurovValeriyTechnical Dep.0x2322322222

Выборку из базы я привел абсолютно произвольную, а теперь суть идеи. «Безопасниками» компании было предпринято вполне благородное решение – шифровать данные о зарплатах, которые очень часто бывают «серыми». Инсайдер получил доступ к базе и сильно обломался, заимев информацию в таком виде. Однако, он не отчаялся и проделал следующий фокус. Резонно предположив, что человек с должностью директора должен получать больше, чем простой менеджер, он поменял соответствующие поля со значениями зарплат одно на другое, тем самым – подложив бухгалтерскому отделу абсолютно левую информацию. В благополучный день такая вещь прокатила, и все безопасники были уволены. Для справки: этим сотрудником был не я, как впрочем, и не безопасником.

Так делать не стоит!

В SQL Server можно создавать четыре типа объектов (хранимые процедуры, представления, пользовательские функции и триггеры) с параметром WITH ENCRYPTION. Этот параметр позволяет зашифровать определение объекта таким образом, что тот можно будет использовать, но получить его определение стандартными способами станет невозможно. Это средство рекомендуется и Microsoft. К сожалению, на практике никакой защиты применение стандартных средств шифрования не обеспечивает! Алгоритм, используемый при шифровании определений объектов, выглядит так:

  1. SQL Server берет GUID той базы данных, в которой создается объект, и значение столбца colid таблицы syscomments для создаваемого объекта (чаще всего, его значение – 1 или 2) и производит их конкатенацию;
  2. Из полученного значения генерируется ключ при помощи алгоритма SHA;
  3. Этот хеш используется в качестве входящего значения при применении еще одного алгоритма хеширования – RSA. С его помощью генерируется набор символов, равный по длине шифруемому определению объекта;
  4. С этим набором символов и с реальным определением объекта производится операция XOR. В результате получаются данные, которые помещаются в столбец ctext таблицы syscomments.

У этой схемы есть два слабых места:

  • Нам ничего не мешает заиметь исходные значения (GUID и colid) для выполнения тех же самых операций и получить ключ на расшифровку. Это можно сделать, например, использовав утилиту dSQLSRVD. Правда, для получения GUID базы данных (и для запуска этой утилиты) нам нужны права системного администратора;
  • Если у нас есть права на создание объектов в базе данных, можно сгенерировать точно такой же ключ для объекта, определение которого нам уже известно (путем сравнения шифрованного определения с незашифрованным). Ну и – использовать его для расшифровки значения другого объекта.

Как можно расшифровать зашифрованные объекты на SQL Server? Есть два варианта:

  • Использовать утилиту dSQLSRVD. Она позволяет выбрать любой зашифрованный объект на сервере и записать его определение в текстовый файл;
  • Использовать хранимую процедуру DECRYPT2K. Код на создание данных хранимых процедур (в разных вариантах и с разными объяснениями), которые расшифровывают определение зашифрованных объектов, легко найти через Google.

WARNING

Использование функций шифрования SQL Server совместно с параметром ANSI_PADDING OFF может привести к потере данных из-за неявных преобразований!

INFO

Не забывай о самых простых истинах традиционной криптографии:

  • Чем более накручен алгоритм шифрования, тем больше ресурсов процессора он будет кушать;
  • Ассиметричная криптография обеспечивает более надежную защиту, чем симметричная (даже с ключами одинаковой длины), но ее исполнение в базах может ощутимо замедлить весь процесс работы;
  • Блочные шифры с длинными ключами надежнее поточных шифров; большой пароль, лучше маленького (вспомни мои пламенные речи об энтропии паролей Армии США) и т.д.

Действия по шифрованию базы напрямую связаны с модификацией обращений клиента. Увы, возможность «прозрачного» шифрования базы на сегодняшний день существует только в MSSQL 2008 (в версии Enterprise). Эта функция именуется там TDE (TransparantDatabase Encryption).

Содержание
загрузка...
Журнал Хакер #151Журнал Хакер #150Журнал Хакер #149Журнал Хакер #148Журнал Хакер #147Журнал Хакер #146Журнал Хакер #145Журнал Хакер #144Журнал Хакер #143Журнал Хакер #142Журнал Хакер #141Журнал Хакер #140Журнал Хакер #139Журнал Хакер #138Журнал Хакер #137Журнал Хакер #136Журнал Хакер #135Журнал Хакер #134Журнал Хакер #133Журнал Хакер #132Журнал Хакер #131Журнал Хакер #130Журнал Хакер #129Журнал Хакер #128Журнал Хакер #127Журнал Хакер #126Журнал Хакер #125Журнал Хакер #124Журнал Хакер #123Журнал Хакер #122Журнал Хакер #121Журнал Хакер #120Журнал Хакер #119Журнал Хакер #118Журнал Хакер #117Журнал Хакер #116Журнал Хакер #115Журнал Хакер #114Журнал Хакер #113Журнал Хакер #112Журнал Хакер #111Журнал Хакер #110Журнал Хакер #109Журнал Хакер #108Журнал Хакер #107Журнал Хакер #106Журнал Хакер #105Журнал Хакер #104Журнал Хакер #103Журнал Хакер #102Журнал Хакер #101Журнал Хакер #100Журнал Хакер #099Журнал Хакер #098Журнал Хакер #097Журнал Хакер #096Журнал Хакер #095Журнал Хакер #094Журнал Хакер #093Журнал Хакер #092Журнал Хакер #091Журнал Хакер #090Журнал Хакер #089Журнал Хакер #088Журнал Хакер #087Журнал Хакер #086Журнал Хакер #085Журнал Хакер #084Журнал Хакер #083Журнал Хакер #082Журнал Хакер #081Журнал Хакер #080Журнал Хакер #079Журнал Хакер #078Журнал Хакер #077Журнал Хакер #076Журнал Хакер #075Журнал Хакер #074Журнал Хакер #073Журнал Хакер #072Журнал Хакер #071Журнал Хакер #070Журнал Хакер #069Журнал Хакер #068Журнал Хакер #067Журнал Хакер #066Журнал Хакер #065Журнал Хакер #064Журнал Хакер #063Журнал Хакер #062Журнал Хакер #061Журнал Хакер #060Журнал Хакер #059Журнал Хакер #058Журнал Хакер #057Журнал Хакер #056Журнал Хакер #055Журнал Хакер #054Журнал Хакер #053Журнал Хакер #052Журнал Хакер #051Журнал Хакер #050Журнал Хакер #049Журнал Хакер #048Журнал Хакер #047Журнал Хакер #046Журнал Хакер #045Журнал Хакер #044Журнал Хакер #043Журнал Хакер #042Журнал Хакер #041Журнал Хакер #040Журнал Хакер #039Журнал Хакер #038Журнал Хакер #037Журнал Хакер #036Журнал Хакер #035Журнал Хакер #034Журнал Хакер #033Журнал Хакер #032Журнал Хакер #031Журнал Хакер #030Журнал Хакер #029Журнал Хакер #028Журнал Хакер #027Журнал Хакер #026Журнал Хакер #025Журнал Хакер #024Журнал Хакер #023Журнал Хакер #022Журнал Хакер #021Журнал Хакер #020Журнал Хакер #019Журнал Хакер #018Журнал Хакер #017Журнал Хакер #016Журнал Хакер #015Журнал Хакер #014Журнал Хакер #013Журнал Хакер #012Журнал Хакер #011Журнал Хакер #010Журнал Хакер #009Журнал Хакер #008Журнал Хакер #007Журнал Хакер #006Журнал Хакер #005Журнал Хакер #004Журнал Хакер #003Журнал Хакер #002Журнал Хакер #001