Создание гибкой инфраструктуры для защиты конфиденциальных данных
Джон, главный администратор базы данных банка Acme Bank, вовлечен в очень важную инициативу, связанную с безопасностью и конфиденциальностью. Джейн, начальник службы информационной безопасности банка, описала стратегию безопасности банка, и Джон определил обязанности своей группы.
Джейн на совещании с ИТ-менеджерами банка Acme объяснила, что безопасность компании можно рассматривать как ряд уровней (слоев) защиты. Для иллюстрации этого Джейн использует "матрешку" - комплект кукол, вкладывающихся одна в другую. Последняя из четырех или пяти этих кукол содержит в себе что-то вроде приза. Чтобы получить приз нужно один за другим удалять "слои" кукол, и если по каким-то причинам слои не могут быть удалены, добраться до приза будет труднее. Джейн объясняет, что злоумышленник, чтобы добраться до корпоративных информационных ресурсов, должен также "победить" много уровней защиты.
Первая полоса обороны - межсетевой экран (МЭ), защищающий всю информационную инфраструктуру организации; он препятствует посторонним получать доступ к любому из информационных источников в компании. Однако никакая организация не является островом и МЭ совсем не воздухонепроницаемы - необходимы "отверстия" или порты, чтобы из внешнего мира мог поступать законный трафик.
Если злоумышленник проходит через внешний МЭ, то он будет обязан предоставить пароль, чтобы получить доступ к серверу, или, возможно, для аутентификации у него будут запрошены другие верительные данные, например, сертификат безопасности. Это - следующий уровень защиты. После аутентификации законному пользователю нужно разрешить доступ только к тем ресурсам, к которым он иметь доступ. Если пользователь подключается к серверу базы данных, но не имеет никаких полномочий, чтобы получить доступ к каким-либо таблицам, представлениям или любым другим источникам данных, информация по-прежнему будет защищена. Этот механизм - следующий уровень защиты.
Джейн подчеркивает, что злоумышленник может так или иначе победить все защитные меры и добраться до данных предприятия. С точки зрения планирования эта возможность должна быть допущена, проанализирована и устранена. Единственный вариант, оставшийся на этой стадии для защиты от злоумышленника, - последний уровень защиты, на котором данные изменяются так, чтобы они не казались злоумышленнику полезными. Это делается с помощью процесса, называемого шифрованием (encryption). Шифрование изменяет данные так, чтобы сделать их неразборчивыми для всех, кроме тех, кто знает, как расшифровать эту информацию.
Шифрование базы данных
После совещания ИТ-менеджеров Джон немедленно собирает своих непосредственных подчиненных для обсуждения стратегии шифрования и ее реализации в своей группе.
Он изложил свою точку зрения на стратегию шифрования, начав с краткого обзора процесса шифрования. Он представляет своей группе простой пример, в котором величина остатка на счете изменена дополнением секретного числа с одной цифрой. Если секретное число будет равно, например, 2, а величина остатка на с счете - 3467, то зашифрованная величина будет равна 3469. Реальная величина может быть расшифрована вычитанием числа 2 из зашифрованной величины, Джон пояснил, что этот процесс называется дешифрованием (decryption). Такую логику добавления определенного числа к реальным данным называют алгоритмом шифрования (encryption algorithm). Число 2, которое добавляется алгоритмом, называется ключом шифрования (encryption key). Исходные данные (original data) и ключ шифрования обрабатываются алгоритмом шифрования для создания зашифрованных данных (encrypted data), как показано рис.1.
Рис 1. Механизм шифрования
При дешифровании для получения исходных данных логика изменятся на обратную. Эта схема также называется симметричным шифрованием (symmetric encryption), поскольку один и тот же ключ используется для шифрования и дешифрования.
Алгоритмы шифрования чаще всего общедоступны; следовательно, безопасность обеспечивается выбором трудно угадываемого ключа. Если бы хакеры в этом примере должны были угадать 1-цифровой ключ, они должны были бы перебрать только 10 чисел - цифры от 0 до 9. Однако, если бы ключ состоял из двух цифр, то они должны были бы перебрать 100 чисел - от 0 до 99. Джон поясняет, чем длиннее ключ, тем более трудно угадать его.
Пакеты, поставляемые с СУБД Oracle
Джон продолжает: в сервере Oracle Database 10
g пользователи могут реализовывать свои методы шифрования, используя функции и процедуры, которые доступны во встроенном пакете
DBMS_CRYPTO. В сервере Oracle Database 10
g и более ранних версиях также доступен другой пакет,
DBMS_OBFUSCATION_TOOLKIT, в котором предлагается подмножество функциональных возможностей пакета
DBMS_CRYPTO. В банке Acme системы работают в среде Oracle Database 10
g, а в более новом пакете
DBMS_CRYPTO предлагаются дополнительные функциональные возможности, кроме того, корпорация Oracle рекомендует использовать именно его, поэтому Джон принял решение использовать этот пакет, и вся аудитория с ним согласилась.
Генерация ключей. Поскольку безопасность зашифрованных данных зависит от трудности угадывания ключа, выбор надлежащего ключа - самый главный шаг в процессе шифрования. Ключ может быть любым значением данных типа RAW, но если оно выбрано не достаточно случайно, злоумышленник будет в состоянии угадать ключ. Джон предупреждает, ключ не может быть, например, именем вашего домашнего животного или вашей датой рождения; это должно быть действительно случайное число. Один младший администратор базы данных спрашивает: "Как вы сгенерируете такой случайный ключ"? Джон отвечает, что случайные числа могут генерироваться с помощью встроенного пакета DBMS_RANDOM, но криптографически стойкая генерация случайных чисел достигается использованием функции RANDOMBYTES в пакете DBMS_CRYPTO. Функция имеет один входной параметр (типа данных BINARY_INTEGER, на выходе выдается число типа данных RAW, длина которого определена входным параметром. Это число может использоваться как ключ. Джон демонстрирует это на примере простого PL/SQL-кода, показанного на листинге 1.
Листинг 1. Шифрование данных
1 declare
2 enc_val raw (2000);
3 l_key raw (2000);
4 l_key_len number := 128;
5 l_mod number := dbms_crypto.ENCRYPT_AES128
6 + dbms_crypto.CHAIN_CBC
7 + dbms_crypto.PAD_PKCS5;
8 begin
9 l_key := dbms_crypto.randombytes (l_key_len);
10 enc_val := dbms_crypto.encrypt
11 (
12 UTL_I18N.STRING_TO_RAW ('SECRET', 'AL32UTF8'),
13 l_mod,
14 l_key
15 );
16 -- Здесь можно использовать зашифрованные данные enc_val
17 end;
Объясняя этот код, Джон обратил внимание, что для проекта шифрования в банке Acme в пакете DBMS_CRYPTO подходит несколько типов алгоритмов и соответствующих длин ключей (см. табл. 1).
Таблица 1. Константы для алгоритмов пакета DBMS_CRYPTO
Первый столбец в табл. 1 - Constant Name (имя константы) - показывает константы, определенные в пакете для указания различных алгоритмов и длин ключей (Effective Key Length). Например, для указания 128-битового ключа, соответствующего стандарту Advanced Encryption Standard (AES, усовершенствованный стандарт шифрования), поясняет Джон, вы используете константу DBMS_CRYPTO.ENCRYPT_AES128 (см. строку 5 листинга 1). Чем длиннее ключ, тем меньше шансов у злоумышленника для его угадывания, но больше работы у сервера для шифрования и дешифрования. Для установления соотношения между безопасностью и нагрузкой на сервер Джон выбирает средний вариант - 128-битовый ключ и алгоритм AES.
Затем определяется тип сцепления, которое при блочном шифровании позволяет разбивать данные на участки для шифрования, как это показано в строке 6 листинга 1. Самый распространенный формат - Cipher Block Chaining (CBC, сцепление блоков шифротекста), указывается в пакете DBMS_CRYPTO константой CHAIN_CBC. Другие варианты сцепления: Electronic Code Book (CHAIN_ECB , электронная книга кодов), Cipher Feedback (CHAIN_CFB, шифрование с обратной связью от шифротекста) и Output Feedback (CHAIN_OFB, шифрование с обратной связью по выходу).
Наконец, поясняет Джон, при блочном шифровании данные обычно шифруются в блоках по восемь символов. Если длина входных данных не кратна восьми, добавляется недостающий символ или символы; этот процесс называется дополнением (padding). Простейший вариант - дополнение нулями. Джон указывает, что этот вариант включается константой PAD_ZERO, определенной в пакете DBMS_CRYPTO, но он не считается достаточно безопасным, поскольку потенциальный злоумышленник может угадать его. Более безопасное дополнение основано на стандарте Public-Key Cryptography Standard # 5 (PKCS#5, криптографический стандарт с общим ключом), задаваемый в пакете DBMS_CRYPTO константой PKCS5, как это показано в строке 7 листинга 1. Если вы уверены, комментирует Джон, что длина данных уже кратна размеру блоков, то дополнения не потребуется, и вы можете указать это с помощью константы PAD_NONE.
Все эти три параметра - алгоритм с длиной ключа, методы сцепления и дополнения - объединяются в один параметр, передаваемый во встроенную функцию шифрования ENCRYPT пакета DBMS_CRYPTO. Функции ENCRYPT требуется, чтобы незашифрованные данные имели тип RAW. Это преобразование делается в строке 12 листинга 1.
В целях стандартизации, продолжает Джон, банк Acme принял решение во всех приложениях использовать алгоритм AES с 128-битовыми ключами, сцепление CBC и дополнение PCKS #5. Используя эти значения, Джон создает простейшую функцию GET_ENC_VAL, показанную на листинге 2, которая принимает только два параметра - исходные незашифрованные данные и ключ - и возвращает зашифрованные данные.
Листинг 2. Простая функция шифрования
1 create or replace function get_enc_val
2 (
3 p_in in varchar2,
4 p_key in raw
5 )
6 return raw is
7 l_enc_val raw (2000);
8 l_mod number := dbms_crypto.ENCRYPT_AES128
9 + dbms_crypto.CHAIN_CBC
10 + dbms_crypto.PAD_PKCS5;
11 begin
12 l_enc_val := dbms_crypto.encrypt
13 (
14 UTL_I18N.STRING_TO_RAW
15 (p_in, 'AL32UTF8'),
16 l_mod,
17 p_key
18 );
19 return l_enc_val;
20* end;
Дешифрование
Джилл, одна из разработчиков Джона, спросила: "Когда нужно расшифровывать зашифрованные данные и как мы будем это делать"?
Джон объясняет, что в пакете DBMS_CRYPTO есть функция дешифрования DECRYPT. Она принимает для дешифрования исходные зашифрованные данные; ключ, использованный во время шифрования; а также объединенный параметр: алгоритм, длина ключа и схемы сцепления и дополнения. Вместе с данными, которые нужно дешифровать, необходимо передавать те же самые ключ и модификаторы, использованные во время шифрования. Банк Acme использует стандартные (одинаковые) алгоритм, длину ключа и схемы сцепления и дополнения, поэтому Джон создал простую функцию для дешифрования зашифрованных данных, показанную на листинге 3. Эта функция принимает только два параметра - зашифрованные данные и ключ - и возвращает расшифрованные данные типа VARCHAR2 (преобразование данных типа RAW делается в строке 20 листинга 3).
Листинг 3. Простая функция дешифрования
1 create or replace function get_dec_val
2 (
3 p_in in raw,
4 p_key in raw
5 )
6 return varchar2
7 is
8 l_ret varchar2 (2000);
9 l_dec_val raw (2000);
10 l_mod number := dbms_crypto.ENCRYPT_AES128
11 + dbms_crypto.CHAIN_CBC
12 + dbms_crypto.PAD_PKCS5;
13 begin
14 l_dec_val := dbms_crypto.decrypt
15 (
16 p_in,
17 l_mod,
18 p_key
19 );
20 l_ret:= UTL_I18N.RAW_TO_CHAR
21 (l_dec_val, 'AL32UTF8');
22 return l_ret;
23* end;
Управление ключами
Занимаясь блочным шифрованием, группа Джона ищет и полное решение для шифрования информации на основе пакета
DBMS_CRYPTO. Самой большой проблемой в шифровании, объясняет Джон, является не генерация ключей или использование функций, а управление ключами, используемыми в процессе шифрования. Одни и те же ключи используются для шифрования и дешифрования данных, поэтому их нужно надежно охранять, чтобы защитить данные. В то же самое время, однако, приложения и пользователи должны иметь доступ к ключам, чтобы дешифровать данные для нормального использования. Эта проблема решается, поясняет Джон, выбором места хранения ключей и обеспечением гарантий, что они будут доступны только законным пользователям. Он предоставляет два варианта управления ключами:
- Использование одного и того же ключа для всех записей.
- Использование разных ключей для разных записей.
В варианте 1, продолжает Джон, для шифрования данных во всех строках используется один ключ. В этом случае для хранения ключа существует несколько вариантов:
- В базе данных.
Для хранения ключа может использоваться таблица ключей, принадлежащая специальному пользователю, который не является владельцем приложений. Джон написал простую функцию, которая всего лишь возвращает ключ в выходном параметре. Пользователи получают привилегии для выполнения этой процедуры, и никакие пользователи не получают каких-либо привилегий для доступа к таблице ключей. В этой функции имеется несколько проверок, обеспечивающих получение ключа только пользователями, которые имеют соответствующие привилегии. Эта функция - единственный источник для получения ключа, поэтому пользователей можно легко аутентифицировать и предоставлять им доступ к ключу.
- В файловой системе.
Хранение ключа в базе данных защищает от большинства злоумышленников, но не от администраторов базы данных, которые могут иметь доступ к любой таблице. Кроме того, может быть очень сложно удостовериться в том, что пользователи, выполняющие запрос, действительно являются законными пользователями. Хранение ключа в файловой системе, к которой администратор базы данных не имеет доступа, например, на другом сервере, таком, как сервер приложений, может оказаться лучшей идеей. Тем не менее, это также означает, что если ключ пропадает из-за повреждения файловой системы, то зашифрованные данные пропадают навсегда.
- У пользователя.
В третьем варианте, показывает Джон, можно разрешить пользователям хранить ключ, например, в карте памяти (мобильного устройства) или на клиентской машине. В этом случае никто кроме законных пользователей не сможет иметь доступ к уязвимым данным. Это особенно полезно в хранилищах данных, в которых зашифрованные данные регулярно посылаются пользователям, уже имеющим ключ. Если по пути данные будут похищены, конфиденциальная информацию будет по-прежнему защищена. Тем не менее, здесь самый высокий риск потери данных, поскольку пользователи чаще всего теряют ключи.
Джон предлагает использовать один ключ для всех записей с хранением его у пользователей для небольшого числа случаев, таких, как публикация итогового контента для различных пользователей, ранее получившим ключ.
Самый большой недостаток этого подхода - уязвимость ключа к воровству. Если ключ украден, все данные в базе данных поставлены под угрозу. Поэтому Джон предложил другой подход для защиты конфиденциальных данных в базах данных OLTP-систем. Такая база данных имеет таблицу ACCOUNT_MASTER, в которой хранится конфиденциальный элемент данных - имя владельца банковского счета (account holder). Столбец, содержащий это имя, ACC_NAME, должен быть зашифрован. Первичный ключ этой таблицы - ACCOUNT_NO. Таблица ACCOUNT_MASTER выглядит примерно так:
SQL> desc account_master
Name Null? Type
---------- -------- ------------
ACCOUNT_NO NOT NULL NUMBER
ACC_NAME VARCHAR2(200)
ACC_TYPE CHAR(1)
Джон предлагает использовать разные ключи для различных строк таблицы
ACCOUNT_MASTER, что устраняет риск
незащищенности данных на уровне всей базы данных, если ключ крадется. Он создает таблицу
ACCOUNT_MASTER_ENC для хранения
зашифрованных данных (имена владельцев счетов) и другую таблицу для хранения ключей,
использованных для шифрования. Эти таблицы -
ACCOUNT_MASTER_ENC и
ACCOUNT_MASTER_KEYS -
выглядят примерно так:
SQL> desc account_master_enc
Name Null? Type
------------ -------- --------
ACCOUNT_NO NOT NULL NUMBER
ACC_NAME_ENC RAW(2000)
SQL> desc account_master_keys
Name Null? Type
---------- -------- ---------
ACCOUNT_NO NOT NULL NUMBER
KEY NOT NULL RAW(2000)
Затем Джон создает представление VW_ACCOUNT_MASTER, показанное на листинге 4, чтобы соединить эти три таблицы для получения расшифрованных данных. Он указывает на строку 8 листинга 4, в которой данные расшифровываются с помощью функции GET_DEC_VAL, рассмотренной выше. Эта функция возвращает данные типа VARCHAR2, поэтому они показываются как столбец VARCHAR2(2000); функция CAST в строке 7 преобразует их в данные типа VARCHAR2(20).
Это представление, не таблица, как раз есть то, что предоставляется для доступа другим пользователям. Джон создает публичный синоним ACCOUNT_MASTER, указывающий на представление VW_ACCCOUNT_MASTER, а не на таблицу с таким же именем как у синонима.
Листинг 4. Представление VW_ACCOUNT_MASTER
1 create or replace view
2 vw_account_master
3 as
4 select
5 m.account_no as account_no,
6 m.acc_type as acc_type,
7 cast (
8 get_dec_val (e.acc_name_enc, k.key)
9 as varchar2(20)) as acc_name
10 from
11 account_master m,
12 account_master_enc e,
13 account_master_keys k
14 where
15 k.account_no = e.account_no
16* and m.account_no = e.account_no;
Публичный синоним ACCOUNT_MASTER указывает на это представление, поэтому пользователи могут извлекать из него данные. Но, спрашивает разработчик Джилл, как же пользователи смогут манипулировать данными в таблице ACCOUNT_MASTER? Используя триггер INSTEAD OF (см. листинг 5), поясняет Джон. Этот триггер модифицирует реальные таблицы, когда пользователи вставляют строки в представление или обновляют его.
Листинг 5. Триггер INSTEAD OF для представления
1 create or replace trigger io_vw_acc_master
2 instead of insert or update on
3 vw_account_master
4 for each row
5 declare
6 l_key raw(2000);
7 begin
8 if (inserting) then
9 l_key := dbms_crypto.randombytes (128);
10 insert into account_master
11 (account_no, acc_type, acc_name)
12 values
13 (
14 :new.account_no,
15 :new.acc_type,
16 :new.acc_name
17 );
18 insert into account_master_enc
19 (account_no, acc_name_enc)
20 values
21 (
22 :new.account_no,
23 get_enc_val (
24 :new.acc_name,
25 l_key )
26 );
27 insert into account_master_keys
28 (account_no, key)
29 values
30 (
31 :new.account_no,
32 l_key
33 );
34 else
35 select key
36 into l_key
37 from account_master_keys
38 where account_no = :new.account_no;
39 update account_master
40 set acc_name = :new.acc_name,
41 acc_type = :new.acc_type
42 where account_no = :new.account_no;
43 update account_master_enc
44 set acc_name_enc =
45 get_enc_val (:new.acc_name, l_key)
46 where account_no = :new.account_no;
47 end if;
48* end;
Пользователи не могут видеть данные непосредственно в таблицах, а только через представление, поэтому информация защищена. Чтобы показывать только зашифрованные данные, защищая исходное содержимое, можно создавать различные представления базовой таблицы.
Дополнительные меры
Джон продолжает обсуждение, детализируя способы хранения ключа шифрования и реализации процесса доступа. Группа обсуждает безопасные контексты приложений, позволяющие использовать только одно представление для работы пользователей с различными уровнями авторизации.
После завершения обсуждения Джон немедленно посылает Джейн электронное письмо, извещая её, что план шифрования готов, и предлагает продемонстрировать его в удобное для неё время.
Арап Нанда (Arup Nanda) (arup@proligence.com) - основатель компании Proligence (Нью-Йорк), предоставляющей высокоспециализированную расширенную поддержку решений Oracle и обучение методам обеспечения информационной безопасности. В 2003 г. он был удостоен награды "Oracle's DBA of the Year"( администратор года баз данных Oracle). Арап - соавтор книги Oracle Privacy Security Auditing (издательство Rampant TechPress, 2003) - "Средства аудита в СУБД Oracle, обеспечивающие информационную безопасность".