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

KDV, www.ibase.ru, 27.25.2013, последнее обновление – 26.02.2014.

Шифрование баз данных и соединений поддерживается с версии 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.
 
Внимание! Рекомендуется после первого логина под SYSDSO поменять пароль, чтобы 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 [as default] [for {AES | DES}]
[with length number-ofbits [bits]]
[password {'user-password' | system encryption password}]
[init_vector {NULL | random}] [pad {NULL | random}]
[description ‘some user description’]

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]

Если указано 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 мегабайт соответственно.

У таблиц есть ПК и по 1 индексу на строковых столбцах данных
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 байт).

Далее я сделал backup/restore, чтобы дальнейшие тесты были чистыми. И, остановив InterBase, сделал для тестов 3 копии исходного файла, в результате должно получиться:
  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.

В результате выполнения операции
------ Performance info ------
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.

Поиск без этого индекса, или по незашифрованному столбцу, проблем не имеет. Например, запрос
select count(*) from street s
where s.name starting with 'Краснооктябрьская'
выдаст 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
where s.name <> 'a'

Для исключения влияния диска запрос выполнялся повторно 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 (и другие книги, при необходимости), можно скачать.
  • Если у вас есть вопросы по статье или предложения по тестированию зашифрованных баз, присылайте их на support@ibase.ru с темой "шифрование в InterBase".
  • Обсуждение статьи на sql.ru
 

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

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

Подпишитесь на новости Firebird в России

Подписаться