Шифрование в базах данных SQL Server. Шифрование соединения средствами MS SQL Server. Создание и присоединение файла рабочей группы

Шифрование баз данных и соединений поддерживается с версии 2009. Данная статья написана по документации и функционалу InterBase XE3. Некоторых опций, указанных в статье, может не быть в предыдущих версиях InterBase - XE, 2009, или могут быть добавлены в последующих - XE7 (XE7, к сожалению, рекомендовать никак не могу, т.к. в любом апдейте этой версии есть баги, которые приводят к повреждениям БД при интенсивной работе).

О шифровании соединений в InterBase изложено . В этой статье описано только шифрование базы данных и/или столбцов таблиц.

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

Обзор шагов шифрования

Для шифрования базы данных и/или столбцов таблиц требуется выполнить последовательно ряд действий. Эти действия, в корректном порядке, перечислены в следующей таблице:
Шаг Задача Кто выполняет
1 Включить EUA, задать пароль SYSDBA владелец БД
2 Создать пользователя SYSDSO (System Database Security Owner) владелец БД
3 Создать System Encryption Password (SEP, системный пароль) SYSDSO
4 Создать ключи для шифрования БД и/или столбцов SYSDSO
5 Дать права пользователю или владельцу БД на использование ключей шифрования SYSDSO
6 Зашифровать БД и/или столбцы владелец БД или пользователь
7 Дать права на чтение зашифрованных данных некоторым пользователям владелец БД или пользователь
Полностью и детально шифрование БД описано в документации на InterBase XE3, в Data Definition Guide, Глава 13, Encrypting Your Data . В этой статье убраны мелкие детали (иначе пришлось бы растянуть это на много страниц). Тем не менее, вы можете выполнять приводимое здесь по шагам над вашей тестовой базой данных, и получить шифрование БД в том или ином виде.

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

1. Включение EUA

Первым требованием перед включением шифрования БД является включение в базе Embedded User Authentification . Эта штука появилась еще в InterBase 7.5 в 2005 году, и позволяет проводить аутентификацию пользователей и SYSDBA через саму БД, а не через общий admin.ib для всех баз на сервере.

EUA является первым средством, которое позволяет защититься от ситуации "украли файл с базой", т. к. если пароль SYSDBA в базе будет не masterkey, то его придется или подбирать, или как-то хакать hex-editor-ом (не пробовал). Но, как минимум, это уже хоть какая-то защита от "чайников".

Итак, берем какую-нибудь тестовую базу, которую не жалко в случае ошибки, и в случае чего можно удалить или пересоздать. База должна быть создана не менее чем в InterBase 2009 (где впервые было сделано шифрование БД), но эту версию уже можно считать устаревшей, поэтому я настаиваю на XE или XE3 (для экспериментов можно взять Developer Edition, если ее у вас ее еще нет - выбираем InterBase XE3 (11.0.3.655) 32-bit Developer Edition - Windows, English или InterBase XE3 (11.0.3.655) 64-bit Developer Edition - Windows, English). Иначе часть описываемых функций у вас может не заработать. Шифрование включается для каждой БД отдельно.

Внимание! Теоретически, все выполняемые ниже действия можно сделать "мышекликаньем" в IBConsole. Однако, как показывает практика, IBConsole глючит, поэтому операции, относящиеся к шифрованию БД, в IBConsole выполнять опасно. Отчасти поэтому, а в основном для того, чтобы вы лучше поняли смысл действий, все команды приведены в виде SQL. Выполнять их можно в любом инструменте - isql, IBExpert, SQL Manager, и т. д.

Логинимся под SYSDBA, включаем в базе EUA

ALTER DATABASE ADD ADMIN OPTION


Меняем пароль SYSDBA

ALTER USER SYSDBA SET PASSWORD "sss"


Понятно, что пароль sss и подобные тут просто для того, чтобы не замучил склероз. Предлагаю по мере выполнения действий записывать их в "блокнотик" с цитатами отсюда, или собственными комментариями - получилось, не получилось, и т. п.

Для упрощения эксперимента можно для всех паролей дальше указывать одно и то же значение, но вы же понимаете, что в реальной ситуации их нужно будет делать разными, поэтому для общей оценки лучше делать именно так.

Разлогиниваемся, проверяем - пароль masterkey больше не работает, используем sss - ок, подключились.

Примечание. С этого момента "вернуть" пароль masterkey подменой admin.ib или переносом базы на другой сервер не получится. То есть, получится, но только отключением EUA, для чего нужно будет знать новый пароль SYSDBA.

2. Создание пользователя SYSDSO

Cоздаем пользователя SYSDSO - SYStem Database Security Owner (его может создать только SYSDBA или владелец БД), который является обязательным для включения шифрования

CREATE USER SYSDSO SET PASSWORD "ooo"


Этот пользователь является "ключником", и не может выполнять никакие другие функции, кроме:
  1. создания системного пароля шифрования (System Encryption Password или SEP)
  2. создания ключей шифрования
  3. выдачи прав другим пользователям на использование созданных ключей шифрования для шифрования базы данных или столбцов таблиц
Больше SYSDSO делать ничего не умеет и не должен.

3. Создание System Encryption Password

Разлогиниваемся, если мы все еще подключены как SYSDBA, логинимся как SYSDSO.

Создаем SEP для базы

ALTER DATABASE SET SYSTEM ENCRYPTION PASSWORD "aaa"

Внимание! При генерации System Encryption Password (SEP) используется информация, специфичная для текущего компьютера. Поэтому на этой машине далее при доступе к БД указывать SEP не требуется (хотя такое требование можно включить), а при переносе БД на другой компьютер никто без указания пароля SEP к базе подключиться не сможет . Можно указывать пароль SEP в параметрах коннекта (isc_dbp_system_encrypt_password), но это доступно только компонентам прямого доступа (типа IBX, FIBPlus, FireDAC, ...). Либо, можно указать SEP в переменных среды ОС (переменная ISC_SYSTEM_ENCRYPT_PASSWORD). Поэтому, если администратор переносит БД на другой сервер, то лучше сделать так - SYSDSO должен залогиниться к базе на новом сервере, используя свой пароль и старый SEP, и создать новый SEP. Новый SEP будет привязан уже к этому компьютеру, и остальным пользователям указывать его при коннекте не потребуется.
Для мобильных платформ с использованием IBLite, где подобные операции проводить как минимум неудобно, нужно явно указывать SEP при подключении к локальной БД.

Если есть желание, чтобы даже сейчас, на этом компьютере, пользователям требовалось указывать при коннекте пароль SEP (если ваше приложение позволяет указывать этот пароль помимо обычного пароля. Если нет, они обломаются, и так лучше не делать), то к данной команде можно добавить в конце опцию EXTERNAL .

Пример параметров для IBX.IBDatabase (или других компонент прямого доступа) с нашими паролями

user_name=SYSDBA
password=sss
lc_ctype=WIN1251


Для баз с SEP, требующим явного ввода, или для баз, перенесенных с конкретного компьютера, дополнительно прописывается (или задается динамически, или вообще запрашивается вместе с логином пользователя, как угодно)

system_encrypt_password=aaa


Пример для FireDAC - TFDConnection.Params

Protocol=TCPIP
Server=myserver
Database=c:\data\ibxes.ib
User_Name=SYSDBA
Password=sss
SEPassword=aaa
DriverID=IB

Внимание! При выборе других (кроме упомянутых FireDAC и IBX) компонент доступа к InterBase/IBLite при использовании шифрования необходимо проверить, поддерживают ли они передачу параметра для пароля SEP. Если нет, часть функций, описанных в статье, вы использовать не сможете. Например, dbExpress такого параметра не имеет, а значит как минимум в отношении зашифрованных баз данных на мобильных платформах его использовать нельзя.

SEP может иметь длину до 255 символов.

Убрать SEP (сделать это может только SYSDSO) можно командой

ALTER DATABASE SET NO SYSTEM ENCRYPTION PASSWORD

4. Создание ключей для шифрования БД и/или столбцов

Дальнейшие действия возможны в двух "опциях". InterBase поддерживает два алгоритма шифрования. DES и AES. DES можно использовать по умолчанию, в том числе в редакциях Trial и Developer, а вот AES можно включить только в полной (купленной) редакции. Впрочем, в использовании DES или AES нет никакой разницы, кроме, разумеется, факта, что AES является более сильным алгоритмом, и пришел на смену DES (для вскрытия которого несколько лет назад были даже созданы специализированные микросхемы). У DES длина ключа 56 байт, у AES - 128-256 байт.

Тем не менее, для проверки будет достаточно DES. Напомню, что шифровать можно как базу целиком, так и отдельные столбцы, поэтому я на всякий случай создам 3 разных ключа шифрования - один буду использовать для базы, и два для столбцов. Физически эти ключи не отличаются. Логинимся под SYSDSO, выполняем команды

CREATE ENCRYPTION db_des for DES
CREATE ENCRYPTION kname_des for DES
CREATE ENCRYPTION sname_des for DES


Все созданные ключи хранятся в таблице RDB$ENCRYPTIONS. Вообще команда CREATE ENCRYPTION сложнее:

create encryption key-name
]


AES или DES - тип ключа

Length - можно использовать только для AES, указывая длину ключа 128, 192 или 256 бит. 128 по умолчанию для AES.

Password - только для ключей, которыми шифруют столбцы, или используют для backup/restore. Можно использовать для дополнительной аутентификации при расшифровке зашифрованных столбцов. Для доступа к такому столбцу нужно или иметь право пользоваться ключом, с помощью которого зашифрован столбец, или знать пароль ключа и перед чтением зашифрованных данных выдать команду

set password "password" for column table.column_name


Init-vector - random включает Cipher Block Changing , при которой для одинаковых значений генерируется разный зашифрованный текст. При null для этого используется Electronic Codebook (в DataDef.pdf на странице 214 это указано как Electronic Cookbook). Null по умолчанию.

Pad - при random padding одинаковые значения могут давать разный результат шифрования. Null по умолчанию.

Description - комментарий к этому ключу - для чего предназначен и т. п.

Внимание! Включение init-vector random или pad random делают невозможным создание индекса по зашифрованному столбцу, при попытке проиндексировать такой столбец сервер выдаст ошибку. Нужно отметить, что и без init-vector и pad с поиском по индексированным зашифрованным столбцам не все хорошо, об этом будет дальше.

Чтобы удалить ключ шифрованиия, нужно выполнить команду

DROP ENCRYPTION имя_ключа


Если указано restrict, то ключ не удалится, если с его помощью уже зашифрованы данные. Если указано cascade, то вместе с удалением ключа будут дешифрованы все столбцы, которые были им зашифрованы.

Выполнять создание и удаление ключей может только SYSDSO.

5. Выдача прав на использование ключей шифрования

Чтобы пользователи могли зашифровать базу или столбцы, SYSDSO должен дать им гранты на использование ключей. Я даю гранты SYSDBA (но можно и кому-то еще):

GRANT ENCRYPT ON ENCRYPTION db_des to SYSDBA;
GRANT ENCRYPT ON ENCRYPTION kname_des to SYSDBA;
GRANT ENCRYPT ON ENCRYPTION sname_des to SYSDBA;


В этом месте я рекомендую сделать бэкап базы, а также отсоединиться от нее (и на всякий случай остановить сервис InterBase) и сделать копию файла. Далее мы будем шифровать базу и столбцы и сравнивать результаты.

Отобрать выданное право на использование ключа можно командой

REVOKE ENCRYPT ON ENCRYPTION FROM SYSDBA


Выполнять эти команды может только SYSDSO.

Тестовая база данных

Чтобы экспериментировать с шифрованием столбцов и базы, нужно чтобы в базе были какие то данные. В качестве готовых я в пустую базу с размером страницы 8192 байт залил данные KLADR - таблицы kladr и street, 190728 и 812609 записей, 17.5 и 98.5 мегабайт соответственно.

ALTER TABLE KLADR ADD CONSTRAINT PK_KLADR PRIMARY KEY (CODE);
CREATE INDEX BY_K_NAME ON KLADR (NAME);
ALTER TABLE STREET ADD CONSTRAINT PK_STREET PRIMARY KEY (CODE);
CREATE INDEX BY_S_NAME ON STREET (NAME);


Незашифрованная БД получилась 136мб (размер страницы 8192 байт).
  1. IBXES.IB - подготовленная к шифрованию база, незашифрованная
  2. IBXESD.IB - зашифрованная БД
  3. IBXESC.IB - база, в которой зашифрованы только строковые столбцы
  4. IBXESDC.IB - зашифрованная БД с зашифрованными столбцами
Исходно, конечно, файлы 2-4 являются эквивалентом ibxes.ib, но затем к ним будет применено то или иное шифрование, и можно будет оценить производительность и особенности каждого варианта.

Тестовый компьютер

Поскольку далее будут приводиться замеры времени выполнения определенных операций, приведу характеристики компьютера, на котором все это делалось, чтобы было с чем сравнить:
  • Процессор: AMD Phenom II X6 1075T
  • Материнская плата: Gigabyte GA-970A-UD3
  • Память: 16Gb, DDR3
  • Видеокарта: GeForce GTX 760
  • Операционная система: Windows 7 Ultimate 64 bit
  • Диск с базой: RAID 1, 2x Seagate ST2000DM001-1CH164 (2Tb, SATA 3).
  • RAID организован чипсетом матплаты, включен кэш Read Ahead и Write Back, для дисков включен NCQ и кэш записи.

6.1 Шифрование базы

Для шифрования всей базы данных выполняем

ALTER DATABASE ENCRYPT DB_DES

То есть, шифруем ее ключом db_des.

В результате выполнения операции


Prepare time = 0ms
Execute time = 10s 265ms
Current memory = 69 980 400
Max memory = 72 140 480
Memory buffers = 8 192
Reads from disk to cache = 16 992
Writes from cache to disk = 10 992
Fetches from cache = 17 143


Шифруются только страницы данных. Не шифруются - Header Page, Log page, Page Inventory Pages, Pointer Pages, Transaction Inventory Pages, Index root Pages, Generator Pages. Размер базы данных после шифрования не изменился.

Определить, зашифрована база или нет, можно вызовом

gstat -h ibxes.ib

При этом строка Attributes будет содержать флаг encrypted (если не зашифрована - этот флаг отсутствует). Для баз, где зашифрованы только столбцы, такая информация не выводится.

Чтобы дешифровать базу (привести в исходное состояние) нужно выполнить

ALTER DATABASE DECRYPT

6.2 Шифрование столбцов

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

Внимание! В документации по InterBase слово decrypt используется в двух смыслах - как для операции, противоположной encrypt, так и для чтения зашифрованных данных. Для исключения путаницы далее я использую следующие слова: дешифрование - процесс, обратный шифрованию; расшифровка - процесс чтения зашифрованных данных.

Шифруем столбец STREET.NAME

ALTER TABLE STREET ALTER NAME ENCRYPT SNAME_DES


IBExpert в Performance Info может выдать такое:

1625218 record(s) was(were) updated in STREET
1625218 record(s) was(were) deleted from STREET
1625218 record(s) was(were) inserted into STREET

А может и не выдать. Причины такого поведения не очень понятны. Кроме того, в таблице STREET на самом деле 812609 записей, т. е. в 2 раза меньше, чем в данном выводе. Один раз вместо 1625218 вышло 2437827, что в 3 раза больше.

Сама операция выполняется мгновенно, потому что шифрование (или дешифрование) данных таблицы происходит по commit. То есть, при выполнении оператора вы увидите разве что

Performance info ------
Prepare time = 0ms
Execute time = 16ms
Current memory = 70 035 744
Max memory = 72 140 480
Memory buffers = 8 192
Reads from disk to cache = 0
Writes from cache to disk = 0


Причем, если это делается сразу после подключения, то commit может занять не более секунды. Возможно, потому, что вся база данных помещается в память. Однако, если выполнить дешифрование столбца, а потом опять повторить шифрование, то уже и дешифрование и шифрование займут существенное время. Например, дешифрование+коммит выполнялось 3 минуты, а последующее шифрование+коммит - 4 минуты. Причем, если такие операции выполняются несколько раз, время выполнения может дойти до 20 минут. Это связано с тем, что в отличие от шифрования страниц целиком шифруются только данные конкретного столбца, а делается это "перевставкой" данных. В итоге таблица начинает "пухнуть", и вместо 98мб получается 104мб, и так далее. Конечно, после этого срабатывает фоновая сборка мусора, и объем таблицы возвращается к прежнему.

Шифрование и дешифрование столбца, поскольку являются операциями alter table, увеличивают счетчик метаданных таблицы (счетчик форматов).

Как уже было сказано выше, если в базе данных зашифрованы только столбцы, а сама база данных не зашифрована, то в выводе gstat -h это никак не отражается. Увидеть признак "зашифрованности" столбца можно только в столбце RDB$ENCRYPTION_ID таблицы RDB$RELATION_FIELDS. В нем хранится код (порядковый номер) ключа шифрования из таблицы RDB$ENCRYPTIONS. Незашифрованные столбцы в этом поле содержат NULL.

Что интересно, для незашифрованного столбца можно выполнить дешифрование, и это займет упомянутое выше время. Вероятно, сервер некорректно обрабатывает null в rdb$encryption_id. К счастью, данные при таком псевдо-дешифровании не портятся.

Для зашифрованных столбцов функции MIN, MAX, BETWEEN и ORDER BY не смогут использовать индекс, поскольку в ключи индекса будут построены по зашифрованным данным (см. дальше).

Для возврата значений столбца в исходное, незашифрованное состояние, нужно выполнить

ALTER TABLE STREET ALTER NAME DECRYPT

Значение по умолчанию при расшифровке

После шифрования столбца, если у пользователя нет прав на расшифровку, он получит сообщение об ошибке при попытке прочитать зашифрованный столбец.

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

ALTER TABLE STREET ALTER COLUMN NAME DECRYPT DEFAULT ""


В данном случае для строкового столбца NAME при отсутствии прав будет выдаваться пустая строка. Для других типов данных указываются соответствующие "пустые" значения - 0, "-", "secured", и так далее.

Если столбец дешифруется, то DECRYPT DEFAULT автоматически удаляется.

Проблема с поиском по индексу

В базе в самом начале был создан индекс BY_S_NAME по столбцу STREET.NAME.

Поиск без этого индекса, или по незашифрованному столбцу, проблем не имеет. Например, запрос

выдаст 55 (столько записей попадают под условие выборки).

Если столбец зашифровать, то запрос выдаст то же число 55. Однако, если начать поиск с одной буквы К до полного Краснооктябрьская, то мы получим такие значения

1 0 0 0 0 0 0 61 0 0 0 0 0 0 0 55 55

То есть, совершенно невразумительные результаты. С одной стороны, прослеживается некая "кратность 8", с другой стороны, непонятно, почему поиск по 1 символу выдал 1 (а не 76732), а по 17ти - выдал не 0, а то же, что и по 16ти.

Поэтому, индексы по зашифрованным строковым столбцам можно считать бесполезными.

Примечание. На других типах данных указанная проблема не проверялась.

6.3 Шифрование и базы, и столбцов

В этом случае выполняем действия пунктов 6.1 и 6.2 (или наоборот). В результате база будет зашифрована одним ключом, столбцы другими ключами. Здесь никаких особенностей, кроме указанных выше, нет.

7. Выдача прав на чтение зашифрованных столбцов

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

CREATE USER TEST SET PASSWORD "test"


Поскольку у нас в базе включено EUA, пользователь попадет не в "серверную" базу admin.ib, а будет храниться именно в нашей базе. Как минимум, это дает преимущество в том, что пользователей можно "включать" и "выключать", а не удалять их, как это делается в случае общей базы пользователей admin.ib. Разумеется, созданный пользователь ни к какой другой базе данных подключиться не сможет, т. к. на уровне "сервера" он не существует.

Дадим пользователю обычные права на чтение таблицы

GRANT SELECT ON STREET TO TEST


Проверим подключение с таким пользователем, и возможность чтения таблицы.

До тех пор, пока мы не будем выбирать столбец NAME, все будет хорошо. Однако, если мы напишем

select * from street

Или при явном перечислении выбираемых столбцов укажем NAME, то может быть два варианта:

  1. получим сообщение

no permission for decrypt access to column NAME by user TEST
если для столбца не было задано DECRYPT DEFAULT

  1. получим пустую строку вместо значений NAME, если для NAME было задано DECRYPT DEFAULT ""
Для того, чтобы дать пользователю видеть зашифрованные данные, нужно выполнить

GRANT DECRYPT (NAME) ON STREET TO TEST


Точно таким же образом права выдаются и ролям, или "общему" пользователю PUBLIC. Или можно дать право расшифровки для VIEW, а уже на VIEW дать пользователям право чтения, без всяких прав на расшифровку.

Отобрать права можно командой

REVOKE DECRYPT (NAME) ON STREET FROM TEST

Производительность

Разумеется, шифрование не дается бесплатно, и потребляет больше процессорных ресурсов. Для проверки на всех четырех типах БД выполнялся один и тот же запрос

select count(*) from street s


Для исключения влияния диска запрос выполнялся повторно 3-4 раза. Таким образом, вся база попадала как минимум в кэш операционной системы.

Результат получился примерно таким:

Здесь слева - время выполнения запроса в секундах. Надо сказать, что на чуть более старом процессоре (и другом железе) отличие получилось более существенным, хотя картина повторилась, например, если нешифрованную базу взять за 1, то зашифрованная была медленнее в 2.2 раз, столбец в 2 раза, и база+столбец - в 3.7 раз. На текущем компьтере максимальная разница не превысила 1.5 раз.

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

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

Backup

Если в базе есть SYSDSO, то бэкапить нужно только с опцией -encrypt и -sep password. Иначе будет выдано сообщение

gbak: ERROR: -encrypt and -sep switches required to back up encryptions


Но если вы попробуете для -encrypt указать любой из уже нами созданных ключей, например, DB_DES, то будет выдана ошибка

gbak: ERROR: encryption DB_DES is not password-protected


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

CREATE ENCRYPTION dbackup for DES password "bbb"

И затем дать право использовать этот ключ тому, кто будет делать бэкап-рестор

GRANT ENCRYPT ON ENCRYPTION dbackup to SYSDBA;


Соответственно, при бэкапе в командной строке указывается, каким ключом шифруется бэкап

Encrypt key_name

А при ресторе указывается пароль для этого ключа

Decrypt key_password


Также, шифрованные базы бэкапятся и ресторятся только через Servcies API .

Таким образом, правильная команда

gbak -b n:\db\ibxe.ib n:\db\ibxe.ibk -user SYSDBA -pass sss -sep ""aaa"" -encrypt dbackup -se service_mgr -v

Обратите внимание на пароль для -sep - он указан в одинарных и снаружи еще и в двойных кавычках.

Restore

Поскольку создать базу на сервере может только SYSDBA/masterkey из admin.ib, а в базе у нас включено EUA, нужно указывать оба набора пользователь/пароль - серверный и для конкретной БД. Кроме того, обязательно использование Services API (опция -se), пароля -sep, и пароля ключа шифрования бэкапа

gbak -с n:\db\ibxe.ibk n:\db\ibxe.ib -user SYSDBA -pass masterkey -eua_u SYSDBA -eua_p sss -sep ""aaa"" -decrypt bbb -se service_mgr -v

Внимание! Каким-то образом по мере экспериментов у меня получилось сделать restore, только в самом конце вылезла ошибка про логин и пароль, а в базе не было ни EUA, ни пользователя SYSDSO, и так далее. Скорее всего, какой-то глюк.

Дополнения

  • Для получения статистики БД (gstat -r ... или через Services API) даже на этом же компьютере почему-то требуется указание System Encryption Password. Для этого gstat имеет дополнительную опцию -sep
  • Как выяснилось, SYSDBA не может сделать ничего "от имени" SYSDSO - попытки создать ключи, удалить ключи, выдать им гранты или напрямую редактировать системные таблицы в этом отношении будут выдавать ошибки типа

data security owner privilege required to encrypt or decrypt.
data security officer privilege required to modify encryption password
action cancelled by trigger (2) to preserve data integrity.
no permission for delete/write access to table RDB$ENCRYPTIONS by user SYSDBA

и т. д.
Однако, SYSDBA может выполнить единственную негативную операцию в отношении SYSDSO - это DROP USER SYSDSO. Как минимум, с целью создать этого пользователя заново с известным SYSDBA паролем, и далее манипулировать ключами "от имени SYSDSO.
Предполагается, что это баг .

  • Если остались непонятные моменты - читайте Data Definition Guide, Глава 13, Encrypting Your Data . Это файл datadef.pdf в каталоге установки InterBase. Документация поставляется во всех дистрибутивах InterBase - Developer Edition, Trial, Server, и так далее. В крайнем случае, datadef.pdf (и другие книги, при необходимости), можно скачать .
  • Если у вас есть вопросы по статье или предложения по тестированию зашифрованных баз, присылайте их на с темой "шифрование в InterBase".

Благодарности

Гаджимурадов Рустам - за мысль о деструктиве SYSDBA в отношении SYSDSO.
Симонов Денис - за предположение, что SYSDBA может манипулировать ключами SYSDSO.
hvlad и WildSery - за указание на ошибки и неточности.

SSL/SSH protects data travelling from the client to the server: SSL/SSH does not protect persistent data stored in a database. SSL is an on-the-wire protocol.

Once an attacker gains access to your database directly (bypassing the webserver), stored sensitive data may be exposed or misused, unless the information is protected by the database itself. Encrypting the data is a good way to mitigate this threat, but very few databases offer this type of data encryption.

The easiest way to work around this problem is to first create your own encryption package, and then use it from within your PHP scripts. PHP can assist you in this with several extensions, such as Mcrypt and Mhash , covering a wide variety of encryption algorithms. The script encrypts the data before inserting it into the database, and decrypts it when retrieving. See the references for further examples of how encryption works.

Hashing

In the case of truly hidden data, if its raw representation is not needed (i.e. will not be displayed), hashing should be taken into consideration. The well-known example for hashing is storing the cryptographic hash of a password in a database, instead of the password itself.

// storing password hash
// $random_chars retrieved e.g. using /dev/random
$query = sprintf ("INSERT INTO users(name,pwd) VALUES("%s","%s");" ,
pg_escape_string ($username ),
pg_escape_string (crypt ($password , "$2a$07$" . $random_chars . "$" )));
$result = pg_query ($connection , $query );

// querying if user submitted the right password
$query = sprintf ("SELECT pwd FROM users WHERE name="%s";" ,
pg_escape_string ($username ));
$row = pg_fetch_assoc (pg_query ($connection , $query ));

if ($row && crypt ($password , $row [ "pwd" ]) == $row [ "pwd" ]) {
echo "Welcome, " . htmlspecialchars ($username ) . "!" ;
} else {
echo "Authentication failed for " . htmlspecialchars ($username ) . "." ;
}

?>

6 years ago

I would strongly recommend using SHA-2 or better the new SHA-3 hash algorithm. MD5 is practically unusable, since there are very well working rainbow tables around the whole web. Almost the same for SHA-1. Of course you should never do a hash without salting!

7 years ago

Using functions to obfuscate the hash generation does not increase security. This is security by obscurity. The algorithm used to hash the data needs to be secure by itself.

I would not suggest to use other data as salt. For example if you use the username, you won"t be able to change the values without rehashing the password.

I would use a dedicated salt value stored in the same database table.

Why? Because a lot of users use the same login credentials on different web services. And in case another service also uses the username as salt, the resulting hashed password might be the same!

Also an attacker may prepare a rainbow table with prehashed passwords using the username and other known data as salt. Using random data would easily prevent this with little programming effort.

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

Чтобы зашифровать или дешифровать базу данных, необходимо быть либо владельцем базы данных, либо, если база данных защищена, членом группы «Admins» с разрешением «монопольный доступ». Перед шифрованием базы данных рекомендуется сохранить ее с другим именем либо на другом диске или папке. В процессе шифрования Microsoft Access не заменяет исходную базу данных до успешного завершения шифрования. Необходимо иметь на диске достаточно места для исходной и зашифрованной версии базы данных.

    Запустите Microsoft Access без открытия базы данных. При работе с сетевой (общей) базой данных убедитесь, что все пользователи закрыли базу данных.

Важно! Нельзя зашифровать или дешифровать открытую базу данных.

    В меню Сервис выберите командуЗащита и подкомандуШифровать/дешифровать .

    Укажите имя базы данных, которую требуется зашифровать или дешифровать, и нажмите кнопку OK .

    Укажите имя, диск и папку для конечной базы данных и нажмите кнопку OK .

Если указаны те же имя, диск и папка, что и у исходной базы данных, а шифрование или дешифрование базы данных выполнено успешно, то исходный файл будет заменен на зашифрованный или дешифрованный. Если же операция приводит к ошибке, то исходный файл удален не будет.

Создание, присоединение и исправление файлов рабочих групп

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

Создание и присоединение файла рабочей группы

Файл рабочей группы содержит список пользователей, совместно использующих данные, также известный как рабочая группа. Пароли пользователей также запоминаются в файле рабочей группы. Для управления доступом к базе данных необходимо создать новый файл рабочей группы.

    Запустите Microsoft Access.

    В меню Сервис выберите командуЗащита , а затем командуАдминистратор рабочих групп .

    В диалоговом окне Администратор рабочих групп нажмите кнопкуСоздать .

    В диалоговом окне Сведения о владельце рабочей группы введите свое имя, название организации и любое сочетание букв и цифр длиной до 20 знаков в качестве кода рабочей группы (WID).

    Введите имя нового файла рабочей группы. По умолчанию файл рабочей группы сохраняется в папке языка. Чтобы сохранить его в другой папке, введите новый путь или нажмите кнопку Обзор , чтобы выбрать новый путь.

    Нажмите кнопку OK .

Новый файл рабочей группы будет использоваться при следующем запуске Microsoft Access. Любые создаваемые учетные записи пользователей и учетные записи групп, а также их пароли, сохраняются в новом файле рабочей группы. Чтобы присоединить к рабочей группе, определенной новым файлом рабочей группы, других пользователей, скопируйте этот файл в общую папку (если он не был сохранен на шаге 5 в общей папке); после этого каждый пользователь должен будет запустить «Администратор рабочих групп» и присоединиться к новому файлу рабочей группы.

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

В более ранних версиях Access можно создать учетные записи пользователей и паролей, используя функцию с именем безопасности на уровне пользователя. В этом разделе рассматривается безопасности на уровне пользователя, который не поддерживается при использовании формате ACCDB.

Зашифрованную базу данных, пароль от которой утерян, невозможно использовать. Если пароль неизвестен, его нельзя удалить.

В этой статье

Обзор

С помощью средства шифрования можно предотвратить чтение базы данных через другие средства и защитить ее паролем. При этом необходимо помнить указанные ниже правила.

    Новая функция шифрования действует только в отношении баз данных в формате ACCDB.

    Это средство использует более стойкий алгоритм шифрования, чем в предыдущих версиях Access.

    При шифровании баз данных, созданных в более ранних версиях Access (MDB-файлов), или применении к ним паролей используются соответствующие функции из Access 2003.

Шифрование базы данных с помощью пароля

В этом разделе описано, как создать пароль и применить к базе данных Access рабочего стола.

Шифрование базы данных

Шифрование разделенной базы данных

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

Открытие и расшифровка базы данных

Напоминание. Обязательно запомните пароль. Забытый пароль невозможно восстановить.

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

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

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

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

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

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

Компания Spelabs (www.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 (www.xpcrypt.com).
Это средство осуществляет весь тот геморрой, который мы только что проделали
вручную. Все, что от тебя требуется, – скачать дистрибутив проги, установить ее
на сервер (к сожалению, есть версия только для Винды), обозначить свою базу
данных и начать химию с таблицами с помощью удобного GUI-интерфейса.

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

Username Password CredCardNum
james god 1234567890123456
lucas sex 2894787650102827
anna love 3234563638716434

Напишем внешнюю функцию 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-битного
ключа). Я бы мог сейчас привести код по генерации публичного и приватного ключа,
но… поступим проще. Все действия можно выполнить из понятного графического
интерфейса, и во многих случаях оставить все на совести программы, не написав ни
строчки кода. И поверь, будет работать!

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

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

ID LastName FirstName Emp
Sum
354 Somov Oleg
IT-Manager M0x8900f56543
643 Antipova Alexandra Director
4343Lax#dsdsss
411 Timurov Valeriy Technical 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.