На этой странице описана функция прозрачного шифрования данных, предложенная в pgsql-hackers.
Он шифрует данные буфера во время ввода-вывода файловой системы:
При кластерном шифровании:
При шифровании на уровне кластера в pg_basebackup будет опция для изменения ключа кучи/индекса для целей ротации ключей. После перехода в резервный режим ключ WAL также можно изменить.
Постоянно ведутся дискуссии о том, можно ли и как реализовать прозрачное шифрование данных (TDE) в Postgres. Многие другие реляционные базы данных поддерживают TDE, и этого требуют некоторые стандарты безопасности.
Однако вопрос о том, какую ценность безопасности обеспечивает TDE, также является спорным.
- Введение
- Что такое TDE и зачем оно понадобилось
- Prerequisites
- Compatibility
- Checksum and Encryption
- TODO for Cluster File Encryption
- Test Data
- TDE — это ещё не вся защита данных
- Управление ключами
- Управление шифрованием
- Резервное копирование и восстановление
- Prepared Transaction Encryption
- Хеширование паролей в PostgreSQL
- Соль
- Функция gen_salt()
- Сохранить новый пароль
- Перемешивание без соли
- Хеширование паролей с использованием случайной соли
- Проверьте правильность введенного пароля
- Предостережения
- Подходы, которых следует избегать
- Расширение pgcrypto
- Особенности, сложности, подходы
- Требования к TDE для промышленной базы данных
- First Principles — Password Hashing
- Практическое использование
- Использование асимметричных ключей
- Генерация ключей
- Шифрование с асимметричным ключом
- Практический совет
- Расшифровка асимметричного ключа
- Расширенное использование
- Настройка хеш-функции
- Объем ТДЭ
- Использование симметричных ключей
- Тип данных BYTEA
- Заключение
- IV для шифрования кучи/индекса
- IV для шифрования WAL
- IV для временных файлов
Введение
Чтобы воспользоваться преимуществами этого руководства, необходимо предварительно познакомиться с PostgreSQL. Для тестирования примеров предполагается, что у вас уже есть PostgreSQL, работающий либо на автономном сервере, либо в качестве экземпляра управляемых баз данных Vultr для PostgreSQL.
Полезно, но не обязательно, быть знакомым с основными понятиями криптографии, такими как шифрование и хеширование.
Обратите внимание, что все примеры кода в этом руководстве представляют собой операторы SQL. Также обратите внимание, что текстовые строки в операторах SQL заключаются в одинарные кавычки.
Что такое TDE и зачем оно понадобилось
Прозрачное шифрование данных (TDE) – тип шифрования данных на диске, при котором данные не шифруются ни при передаче, ни в памяти.
TDE — важная фича, особенно для финансовых организаций, которым приходится иметь дело с различными стандартами безопасности.
Прозрачное шифрование данных от открытия при хищении дисков или файлов с данными СУБД, в том числе резервных копий. А ещё ограждает от подмены данных через их изменение в файлах: обеспечить шифрование данных без ключа всё равно не получится, только порча.
В общем, стало понятно, что для Pangolin просто необходимо прозрачное шифрование, которое бы проверяло соответствие требованиям корпораций, а по скорости и надёжности не уступало бы аналогичным промышленным базам данных.
Привет, Хабр! Меня зовут Владимир Харчиков, я разрабатываю и сопровождаю Platform V Pangolin в СберТехе. Панголин ― реляционная СУБД, созданная нами для хранения и обработки данных в высоконагруженных приложениях.
В статье я рассказываю, как рассказывает о скорости обработки транзакций и безопасности хранения данных, а именно о реализации функции прозрачного шифрования данных внутри нашего СУБД. Кому эта тема интересна ― прошу под кат.

Немного про Платформа V Панголин
Когда Сбер несколько лет назад начал процесс импортозамещения и постепенного отказа от решений западных вендоров, перед нами стояла задача создать собственное ПО, которое будет соответствовать требованиям крупнейшего банка страны к функциональности СУБД, ее производительности, безопасности, отказоустойчивости.
Так появилась платформа V Pangolin, реляционная СУБД, основанная на наших экологически устойчивых разработках и хорошо зарекомендовавшая себя открытым ПО (PostgreSQL).
Шифрование для отдельных столбцов
Модуль pgcrypto позволяет хранить определенные поля в зашифрованном виде. Это полезно, если конфиденциальны только некоторые данные. Клиент предоставляет ключ дешифрования, и данные расшифровываются на сервере, а затем отправляются клиенту.
Шифрование раздела данных
Этот механизм предотвращает чтение незашифрованных данных с дисков в случае кражи дисков или всего компьютера. Это не защищает от атак, пока файловая система смонтирована, поскольку при монтировании операционная система обеспечивает незашифрованное представление данных. Однако для монтирования файловой системы вам нужен какой-то способ передачи ключа шифрования в операционную систему, и иногда ключ хранится где-то на хосте, который монтирует диск.
Шифрование данных в сети
или также может использоваться для шифрования передаваемых данных.
SSL-аутентификация хоста
И клиент, и сервер могут предоставлять друг другу SSL-сертификаты. Для каждой стороны требуется дополнительная настройка, но это обеспечивает более надежную проверку личности, чем простое использование паролей. Это не позволяет компьютеру притворяться сервером на время, достаточное для того, чтобы прочитать пароль, отправленный клиентом. Это также помогает предотвратить атаки «человек посередине», когда компьютер, находящийся между клиентом и сервером, выдает себя за сервер и считывает и передает все данные между клиентом и сервером.
Шифрование информации в базе данных называется шифрованием покоя. Это отличается от шифрования при передаче. Encryption at rest can be done at three different layers:
The scope of this article is limited to encrypting the data in specific columns. The use of both symmetric key encryption and public (asymmetric) key encryption is covered. This article does not cover TDE or disk-level encryption.
Prerequisites
It is helpful, but not mandatory, to be familiar with the basic concepts of cryptography, like encryption and decryption, symmetric and asymmetric keys, and the like.
Compatibility
Encrypting data columns using the pgcrypto extension works on all recent versions of PostgreSQL. The commands in the section on generating public and private keys are based on the GNU PG (GNU Privacy Guard) tool, gpg. A default installation of most common Linux distros includes gpg. There exist similar tools for Mac, Windows, and other Operating Systems, but their usage is not covered in this guide. Key generation commands in this article are tested on Ubuntu 22.04. In general, they should be compatible with all recent Linux releases.
Checksum and Encryption
It is unclear if the page CRC should be encrypted. If encrypted, it gives cryptographically-insecure integrity checking but requires command-line tools that check the CRC to have access to the encryption key.
TODO for Cluster File Encryption
Here is list of ongoing tasks with there assignment and status for cluster-wide encryption:
Here are some tasks or areas that we need to research, some of these are being worked as part of main to do’s listed above. This is a exhaustive list to ensure that we don’t skip any todo required for the
first phase of TDE.
Test Data
CREATE TABLE patients (id SERIAL, name VARCHAR
, notes_symmetric TEXT UNIQUE, notes_asymmetric TEXT UNIQUE) ;
The examples below encrypt and insert mock excerpts of clinical notes about hypothetical patients:
TDE — это ещё не вся защита данных
Чтобы обеспечить защиту пользовательских данных, в СУБД должна быть реализована возможность разделять привилегии и действия, доступные пользователям с различным уровнем доступа.
Рассмотрим роли привилегированных пользователей, имеющих доступ к данным, и тактику защиты от злоумышленников, обладающих каждой из этих ролей:
Очевидно, что для полной защиты пользовательских данных одного TDE недостаточно. Шифрование не препятствует выполнению авторизованных запросов и не закрывает риски, связанные с тем, что расширения PostgreSQL могут получить доступ к незашифрованным данным в памяти.
Чтобы обеспечить комплексную безопасность данных, в Platform V Pangolin реализована защита от привилегированных пользователей и контроль расширений PostgreSQL, в рамках которого каждое расширение проверяется нашей командой, а двоичный образ подписывается.
Вот, в целом, и всё. Если у вас есть вопросы ― задавайте в комментариях, постараюсь на все ответить. И если есть варианты решения озвученных проблем ― поделитесь собственными кейсами, пожалуйста.
Управление ключами
Структура ключей сделана двухуровневой. Для каждого объекта — таблицы, индекса, материализованного представления — генерируется новый ключ, который помещается в хранилище ключей (keyring). Хранилище размещается в общей памяти PostgreSQL.
Ключи шифрования объектов перманентно хранятся в директории global БД в виде файла. Ключи в файле зашифрованы мастер-ключом, содержат указание на версию мастер-ключа и контрольный блок. Он позволяет понять, что для расшифровки объекта использован правильный мастер-ключ. В противном случае при ротации мастер-ключа вместо ключа шифрования объекта можно получить мусор.
Файл с ключами включается в резервную копию БД. Мастер-ключ хранится в хранилище секретов. Там же хранится история изменения мастер-ключей, указание на метку активного мастер-ключа и ключ шифрования реплицируемых данных для потоковой и логической репликации.
Двухуровневая система решает две задачи:
В качестве хранилища секретов используется Hashicorp Vault. Интеграция реализована через поддержку механизма плагинов интеграции с хранилищем секретов, что позволяет при необходимости реализовывать и включать поддержку и других типов хранилищ без необходимости выпускать новую версию продукта.
На скриншоте ниже — пример структуры хранения ключей в Hashicorp Vault:

Поддерживается ротация мастер-ключей как через функции БД, так и на стороне хранилища секретов.
При ротации на стороне хранилища секретов нужно соблюдать структуру хранения параметров, как показано выше. При этом на стороне СУБД работает фоновый процесс, периодически проверяющий изменение мастер-ключа и выполняющий перешифрование ключей в локальном keyring БД.
Функции для поддержки ротации и изменения мастер-ключей на стороне БД следующие:
В процессе ротации самым сложным было исключить ситуации, при которых изменение мастер-ключей и перешифрование keyring будет конкурировать с использующими их процессами и утилитами.
Для ключей в keyring ротация пока не реализована, так как смена ключа шифрования тривиальным способом вынуждает провести единовременное перешифрование большого объёма данных с блокировкой доступа к данным на это время. Планируем реализовать функциональность в ближайшее время и рассматриваем два варианта:
Ввести ещё один форк для файлов отношений, лежащий рядом с файлами main-форка. Форк будет предназначен для хранения идентификатора ключа шифрования из keyring, которым зашифрован конкретный блок main-форка отношения.
Использовать свободные биты в поле pd_flags заголовка страницы для указания на какой-либо из N последних ключей из истории ключей в keyring для отношения.
Любой из этих подходов позволит нам проводить отложенное перешифрование отдельных страниц, а не единовременно менять ключ шифрования для всего отношения с полным перешифрованием:
Управление шифрованием
Шифруется объект или нет, зависит от того, в каком табличном пространстве он находится. Для создания шифрованных табличных пространств добавлена опция в команду CREATE TABLESPACE:
Смена значения опции is_encrypted запрещена, так как это потребует шифрования или расшифровки всех данных, хранимых в табличном пространстве;
Создание ключа для шифрованного объекта отражается в WAL для обеспечения целостности и репликации ключа на резервные БД. При логической репликации передача ключей шифрования не поддерживается;
При переносе объекта из шифрованного в нешифрованное табличное пространство выполняется расшифровка данных;
При удалении отношения его ключ помечается на удаление из keyring при коммите соответствующей транзакции. При последующем checkpoint’е происходит удаление помеченных на удаление ключей из keyring, так как размер keyring ограничен.
Для настройки TDE введены дополнительные параметры в конфигурации PostgreSQL:
Интеграция с хранилищем секретов настраивается в 2 этапа:
Выбор плагина для интеграции с соответствующим задаче интерфейсом и создание из libdi-инсталляции символической ссылки с фиксированным именем на библиотеку плагина. Плагин предоставляет функции инициализации плагина, проверки работоспособности, чтения и установки значений параметров, а также функцию для check-and-set-установки значения параметра, если такая возможность поддерживается соответствующим хранилищем. В зоне ответственности плагина находятся все вопросы, касающиеся особенностей взаимодействия с хранилищем секретов, включая аутентификацию, авторизацию и протоколы взаимодействия.
Настройка параметров, специфичных для плагина. Способ настройки зависит от конкретной реализации плагина.
Настройка используемого провайдера шифрования выполняется через указание динамически подгружаемой библиотеки шифрования путём создания символической ссылки с фиксированным именем из lib-директории инсталляции PostgreSQL на требуемую библиотеку. Криптографические плагины предоставляют функции получения размера ключа и инициализирующего вектора, генерации ключа, шифрования и расшифровки заданного блока данных с заданным ключом и вектором инициализации.
Резервное копирование и восстановление
При резервном копировании файлы данных передаются в том виде, в котором хранятся. В резервную копию включается файл keyring, зашифрованный мастер-ключом, актуальным на момент снятия резервной копии. Поднять базу из резервной копии на сервере, не имеющем настроенного доступа к хранилищу секретов с валидными для БД ключами шифрования, не получится.
При запуске экземпляра после восстановления БД из резервной копии будет проведена проверка совпадения метки мастер-ключа, которым был зашифрован keyring на момент снятия резервной копии, с меткой актуального мастер-ключа. При несовпадении меток будет выполняться процедура, реализованная в функции restore_keys (см. выше): она выполняет перешифрование keyring актуальным мастер-ключом. После успешного перешифрования база данных будет открыта.
Prepared Transaction Encryption
During the discussion, the point about prepared transaction encryption also came up since they are also persisted. Sawada-san mentioned that we aren’t storing any important data for prepared transactions
so we might not need to encrypt it. Однако нам нужно, чтобы это было частью списка дел.
Хеширование паролей в PostgreSQL
В PostgreSQL расширение pgcrypto имеет необходимые функции для хеширования паролей. Поскольку pgcrypto является встроенным расширением, вам не нужно загружать или устанавливать для него какое-либо дополнительное программное обеспечение. Включить расширение:
СОЗДАТЬ РАСШИРЕНИЕ pgcrypto ;
Соль
Хэш-функция всегда генерирует один и тот же хэш для данной входной строки. Это приводит к двум основным проблемам:
Функция gen_salt()
Соль генерируется с помощью функции gen_salt(). Обычно эта функция принимает один аргумент — тип. Синтаксис:
— псевдокод
gen_salt (тип) ;
Аргумент типа обозначает тип криптографического алгоритма, который будет использоваться для хеширования. Он может принимать одно из четырех возможных значений:
Например, для генерации соли с использованием расширенного алгоритма DES:
SELECT gen_salt(‘xdes’) ;
Аналогично, чтобы сгенерировать соль с помощью алгоритма MD5:
SELECT gen_salt(‘md5’) ;
Сохранить новый пароль
Синтаксис функции crypt():
— псевдокод
crypt(строка_пароля, строка_соли) ;
Аргумент salt_string генерируется с помощью функции gen_salt(). Например, чтобы использовать алгоритм md5 для вычисления хеша:
— псевдокод
SELECT crypt(password_string, gen_salt(‘md5’));
Перемешивание без соли
Чтобы имитировать использование функции crypt() без рандомизированной соли, используйте для соли константную строку salt. Сгенерируйте хеш для пароля supersecurepassword:
SELECT crypt(‘supersecurepassword’, ‘salt’) ;
Приведенная выше команда генерирует зашифрованный текст saUkChKIZTKFs. Нерандомизированная соль (или отсутствие соли) приводит к предсказуемым хэшам и делает систему уязвимой для атак с использованием радужных таблиц. Следовательно, необходимо использовать рандомизированные соли.
Хеширование паролей с использованием случайной соли
Сгенерируйте хеш для строки пароля supersecurepassword, используя, например, алгоритм MD5:
SELECT crypt(‘supersecurepassword’, gen_salt(‘md5’)) ;
Скопируйте значение хеш-функции, сгенерированное приведенной выше командой. Вы будете использовать его в следующем разделе.
Проверьте правильность введенного пароля
Если введенный пароль совпадает с фактическим паролем, хэш введенного пароля совпадает с сохраненным хешем (фактического пароля).
Общий синтаксис:
—псевдокод
crypt(введенный_пароль, сохраненный_хэш_фактического_пароля) ;
SELECT crypt(‘supersecurepassword’, ‘generated_hash_value_from_actual_password’) ;
Второй аргумент выше — это хэш, сгенерированный предыдущей командой — вставьте хэш-значение, которое вы скопировали ранее. Эта команда выводит тот же хэш, который был сгенерирован реальным паролем.
SELECT crypt(‘неправильный_пароль’, ‘сгенерированное_хэш_значение_from_actual_password’) ;
Выходное хэш-значение отличается от хэша фактического пароля.
Другими словами, вызов функции crypt() со строкой (строка1) и хешем (хеш1) этой строки (строка1) генерирует один и тот же хеш (хеш1).
Предостережения
Шифрование данных в отдельных столбцах — это детальный подход, который хорошо работает во многих случаях использования. Однако его использование имеет некоторые оговорки:
Подходы, которых следует избегать
Внедрение шифрования столбцов — это разовая операция. Обеспечение доступа к ключам является постоянной оперативной задачей. Скомпрометированная база данных не должна приводить к компрометации данных — это противоречит цели шифрования.
Ключ удобно хранить либо в самой базе данных, либо как часть хранимой процедуры. Не делай это. Если злоумышленник получит доступ к базе данных (или ее дампу), он также получит доступ к ключам. Ключ должен храниться отдельно от зашифрованных данных.
Точно так же можно сохранить экспортированный файл ключей в каталоге данных PostgreSQL. Это позволяет приложению напрямую обращаться к файлу ключей из SQL-запроса, например:
—псевдокод
pgp_pub_decrypt(‘зашифрованные конфиденциальные_данные’, Dearmor(pg_read_file(‘/path/to/key_file’)))
Хотя этот подход удобен, он небезопасен. Злоумышленник, скомпрометировавший сервер базы данных, также получает доступ к ключам. Следовательно, как и раньше, храните ключ отдельно от данных.
Расширение pgcrypto
Шифрование в PostgreSQL основано на стандарте OpenPGP. Расширение pgcrypto имеет необходимые функции для шифрования и дешифрования данных по стандарту OpenPGP. Since pgcrypto is a builtin extension, you do not need to download or install any additional software for it. Enable the extension:
Особенности, сложности, подходы
С самого начала было понятно, что реализовать шифрование как расширение PostgreSQL не получится: нужно менять поведение системы в точках, не имеющих необходимых хуков.
Чтобы повысить надёжность защиты, помимо шифрования страниц с данными решили реализовать шифрование в следующих объектах:
Если данные реплицируются между экземплярами БД, то все экземпляры, участвующие в репликации, должны уметь шифровать данные и иметь доступ к одним и тем же ключам шифрования. Это позволит исключить сценарий кражи данных через репликацию на неавторизованный экземпляр БД. Сценарий выглядит немного параноидально, но он необходим, так как TDE участвует в решении более глобальной проблемы — защите пользовательских данных от привилегированных пользователей, включая администраторов СУБД.

Также некоторые утилиты PostgreSQL работают с данными в WAL напрямую, без обращения к API самой СУБД. Все эти утилиты пришлось доработать:
Все эти утилиты мы «обучили» расшифровке журналов при чтении. Утилита pg_resetwal изменяет журнал, поэтому её пришлось «обучать» и расшифровке, и шифрованию. Утилиты pg_basebackup и pg_receivewal не модифицировали, так как им не нужен доступ к структуре получаемых данных.
При шифровании используются симметричные алгоритмы, поскольку они быстрее, а асимметрия в данном случае просто не нужна. На первом этапе в качестве провайдера шифрования выступают движки библиотеки OpenSSL и алгоритмы AES CBC/CTR/GCM с длиной ключа 128/192/256 бит (движок builtin, алгоритмы SN_aes_128_*, SN_aes_192_*, SN_aes_256_*).
В тестовых целях сделали интеграцию шифрования по ГОСТ из состава OpenSSL (движок gost, алгоритмы SN_id_Gost28147_89/NID_gost89_cbc, SN_gost89_cnt/NID_gost89_cnt_12). Но использовать её по умолчанию не получилось из-за низкой скорости. В отличие от AES-NI/PadLock, для шифрования по ГОСТ отсутствует аппаратная поддержка.
Поддержка алгоритмов шифрования реализована через механизм динамически подгружаемых библиотек-обёрток над провайдерами шифрования.
Инициализирующие векторы уникальны для каждого куска данных, а алгоритм формирования вектора зависит от типа шифруемых данных. Например, для страниц данных используется информация из заголовка страницы и номер страницы, а для временных данных генерируется случайный вектор, сохраняемый в общей памяти до тех пор, пока есть необходимость доступа к этим данным.
Непосредственно шифрование/дешифрование происходит в точках передачи данных из памяти на диск или в сеть и наоборот.
Для данных отношений. Основные изменения были сделаны в buffer manager (bufmgr.c) в функциях, выполняющих чтение с диска в буферный кэш (ReadBuffer_common) и запись из буферного кэша на диск (FlushBuffer, FlushRelationBuffers). Модификация именно в этих функциях позволила сократить изменения в коде, так как функциональность, требующая работы с буферным кэшем, использует в конечном счёте именно эти функции для чтения страниц с диска или записи страниц на диск.
Для данных временных таблиц. Всё почти аналогично данным постоянных отношений. Пришлось изменить только функцию выделения новой страницы буферного кэша LocalBufferAlloc для local buffer manager’а (localbuf.c), так как в ней было реализовано собственное сохранение dirty-страниц при необходимости освобождения памяти в буферном кэше.
Для временных данных, выгружаемых на диск при сортировках и join’ах. TDE поддерживали в функциях buffile.c, служащих для записи и чтения буферизируемых временных файлов.
Для записей WAL. Реализовали шифрование в xlog.c в создании нового сегмента WAL и в записи WAL. В процессе walreceiver перешифрование реализовано только при смене временной линии, где меняется инициализирующий вектор шифрования. В остальных случаях приходящие записи складываются в WAL как есть, так как они поступают уже в зашифрованном виде.
Для потоковой репликации. Изменений нет, записи WAL передаются как есть, так как они уже лежат в зашифрованном виде.
Для логической репликации. Реализовано шифрование и расшифровка передаваемых данных через заполнение добавленного callback page_cipher в XLogReaderRoutine в slotfuncs.c, walsender.c и logicalfuncs.c.
Требования к TDE для промышленной базы данных
Если коротко, то мы сформулировали требования к прозрачному шифрованию так:
First Principles — Password Hashing
A hash is a random-looking string that is generated from an input string. The algorithm that generates the hash is called a hash function. Вычислить хеш входной строки легко, но почти невозможно вычислить значение строки по ее хешу. Говорят, что хеширование — это одностороннее вычисление.
Таким образом, наиболее практичным вектором атаки на хешированные пароли является перебор. Попытки перебора обычно основаны на словарях. Общая идея состоит в том, чтобы начать со списка (словаря) наиболее часто используемых паролей и последовательно вычислять хеш каждого возможного пароля, пока не будет найдено совпадение.
Хеширование представляет собой трудоемкую вычислительную задачу; это затрудняет брутфорс. Кроме того, функции хеширования паролей используют такие методы, как растяжение ключей, для дальнейшего замедления попыток подбора пароля. Примером метода растяжения ключа является многократное хеширование строки (сначала вычисление хэша, затем хэша хеша и т. д.).
Практическое использование
При фактическом использовании хеши хранятся в таблицах и запрашиваются из них. Примеры в этом разделе показывают, как это сделать:
Вставьте в таблицу строку тестовых данных:
Чтобы сопоставить введенный пароль с правильным паролем, вызовите функцию crypt() с введенным паролем и хешем правильного пароля в качестве соли.
Это должно вывести t в качестве значения true как значение пароля_match.
Это должно вывести f, как значение false, как значение пароля_match.
Использование асимметричных ключей
—псевдокод
шифр = функция_шифрования (открытый текст, открытый_ключ)
открытый текст = функция_дешифрования (шифр, секретный_ключ)
Генерация ключей
Чтобы использовать шифрование с асимметричным ключом, вам нужна пара ключей (открытый и закрытый ключи). Обратите внимание, что ключи PGP могут быть сгенерированы только в операционной системе, а не в PostgreSQL. Сгенерируйте пару ключей с помощью gpg:
$ gpg —gen-key
Приведенная выше команда запрашивает имя и адрес электронной почты. После создания пары ключей вы получаете возможность установить парольную фразу. Чтобы пропустить этот шаг, нажмите Enter, не вводя парольную фразу.
Если вы ввели парольную фразу, запомните ее (или запишите) для дальнейшего использования. Парольная фраза необходима для расшифровки, а не для шифрования. Без парольной фразы расшифровать данные невозможно — функция «забыли пароль» отсутствует.
Чтобы проверить все сгенерированные ключи:
$ gpg —list-keys
Здесь перечислены все сгенерированные пары ключей. Каждая пара ключей отображается, как показано в примере ниже:
Экспортировать открытый ключ:
Взгляните на файл открытого ключа:
$ меньше ~/.my_public_key.txt
Обратите внимание, что ключ находится в двоичном формате — это затрудняет его обработку, особенно в часто используемых текстовых интерфейсах. Для копирования и вставки ключ должен быть выражен в формате ASCII. Это достигается путем перевода ключа из двоичного кода в ASCII. Опция —armor команды gpg делает следующее:
Взгляните еще раз на файл открытого ключа:
Открытый ключ теперь доступен для чтения и выглядит следующим образом:
Аналогичным образом экспортируйте бронированный закрытый ключ:
Если вы установили парольную фразу, вас спросят об этом при экспорте закрытого ключа.
Взгляните на (бронированный) закрытый ключ:
$ меньше ~/.my_private_key.txt
Закрытый ключ выглядит так:
Шифрование с асимметричным ключом
Чтобы зашифровать данные с использованием асимметричного шифрования, используйте функцию шифрования pgp_pub_encrypt():
—псевдокод
pgp_pub_encrypt(‘конфиденциальные данные для шифрования’, ‘public_key’)
Функция шифрования вызывается при вставке данных в таблицу. Для функции шифрования требуется ключ в двоичном формате. Таким образом, ключ снова переводится из текстового формата ASCII в двоичный. Это делается с помощью функции Dearmor().
—псевдокод
pgp_pub_encrypt(‘конфиденциальные данные для шифрования’, Dearmor(‘public_key’)) ;
Чтобы вставить в таблицу фиктивные строки с данными пациента:
ВСТАВИТЬ В пациентов (имя, примечания_асимметричный)
ЦЕННОСТИ (
«Джейн Доу 2»,
pgp_pub_encrypt(
«У 66-летней женщины в течение последних 2 недель наблюдаются симптомы боли в нижних левых коренных зубах. Никаких проблем с зубами в анамнезе не было. Курю время от времени.’,
дорогоймор(‘public_key’)
)
) ;
В приведенном выше коде скопируйте бронированное значение public_key из экспортированного текстового файла, как описано ранее.
Аналогично вставьте еще одну строку фиктивных данных:
ВСТАВЬТЕ В пациентов (имя, примечания_асимметричные)
ЦЕННОСТИ (
«Джон Доу 2»,
pgp_pub_encrypt(
«66-летний мужчина жалуется на симптомы боли в нижней левой части живота в течение последних 2 недель. Никаких проблем с почками в анамнезе не было. Иногда пьет.’,
дорогоймор(‘public_key’)
)
) ;
В примерах предыдущего раздела данные пациента, зашифрованные с использованием симметричных ключей, были вставлены в столбец Notes_symmetric. В примерах этого раздела данные пациента шифруются с использованием асимметричных ключей и вставляются в столбец Notes_asymmetric.
Практический совет
На практике ключи являются частью кода приложения, которое считывает/записывает данные из/в базу данных. В этих примерах вы вручную копируете и вставляете ключи. Вставка многострочных строк (например, открытых и закрытых ключей) в командной строке затруднительна. Чтобы опробовать примеры, рекомендуется использовать интерфейс базы данных на основе графического пользовательского интерфейса (например, Postico на Mac или Beekeeper Studio на Ubuntu или любое другое удобное для вас программное обеспечение) для доступа к базе данных и ввода команд SQL.
Расшифровка асимметричного ключа
Чтобы расшифровать данные (которые были зашифрованы с использованием открытого ключа), вам понадобится закрытый ключ. Вызовите функцию pgp_pub_decrypt() для зашифрованных данных:
—псевдокод: использование парольной фразы
pgp_pub_decrypt(‘зашифрованные конфиденциальные данные’, ‘private_key’, ‘парольная фраза’)
—pseudocode: без парольной фразы
pgp_pub_decrypt(‘зашифрованные конфиденциальные данные’, ‘private_key’)
Как и раньше, текстовое значение ASCII закрытого ключа также преобразуется в двоичный формат перед его использованием. Расшифруйте столбцы, содержащие зашифрованные данные:
—используя парольную фразу
ВЫБИРАТЬ
имя,
pgp_pub_decrypt(
Notes_asymmetric::BYTEA,
дорогоймор(‘private_key’),
‘парольная фраза’
)
ОТ пациентов;
В приведенном выше примере скопируйте значение Private_key из текстового файла, описанного ранее. Напишите парольную фразу, которую вы установили ранее, в одинарных кавычках. Если вы не задали парольную фразу, опустите этот аргумент при вызове функции:
—без парольной фразы
ВЫБИРАТЬ
имя,
pgp_pub_decrypt(
Notes_asymmetric::BYTEA,
дорогой(‘private_key’)
)
ОТ пациентов;
Чтобы выполнить запрос с условием фактического (незашифрованного) значения зашифрованного столбца, основывайте условие на значении расшифрованного столбца. Например, чтобы найти пациентов, в чьих записях упоминается слово курить:
ВЫБРАТЬ
имя,
pgp_pub_decrypt(
Notes_asymmetric::BYTEA,
дорогоймор(‘private_key’),
‘парольная фраза’
)
ОТ пациентов
ГДЕ pgp_pub_decrypt(
Notes_asymmetric::BYTEA,
дорогоймор(‘private_key’),
‘парольная фраза’
) НРАВИТСЯ ‘%smoke%’ ;
Расширенное использование
Когда хэш вычисляется с использованием алгоритмов Extended DES или Blowfish, можно настроить (настроить) количество итераций, которые алгоритм выполняет для генерации хеша. В этом случае функция gen_salt() может принимать дополнительный аргумент iter_count для количества итераций. Синтаксис:
— псевдокод
gen_salt(type, iter_count)
В приведенном выше операторе тип — xdes или bf.
Если хэш был сгенерирован после N итераций, любая попытка грубого подбора также должна хешировать подборы пароля N раз. Чем больше значение N, тем сложнее подобрать хэш пароля. Однако слишком медленное вычисление хеша непрактично для регулярного использования. В качестве демонстрации хешируйте пароль supersecurepassword с использованием алгоритма Blowfish с количеством итераций по умолчанию 6:
.
SELECT crypt(‘supersecurepassword’, gen_salt(‘bf’, 6)) ;
Заметьте, сколько примерно времени это занимает (по часам на компьютере или телефоне). Теперь запустите ту же хэш-функцию с большим количеством итераций:
SELECT crypt(‘supersecurepassword’, gen_salt(‘bf’, 30)) ;
Это занимает гораздо больше времени. Если это занимает слишком много времени, отмените операцию с помощью CTRL + C и повторите попытку с меньшим количеством итераций.
Если вы введете неверное количество итераций, выдаст такую ошибку:
ОШИБКА: gen_salt: неправильное количество раундов
Настройка хеш-функции
Конечно, TDE — единственный способ шифрования данных. Есть и другие варианты. Например, шифрование отдельного колонка на стороне пользователя, где все сопутствующие процедуры должны быть реализованы в приложении.
Но подход такой усложняет работу: пользовательская сторона сама должна выполнять операции, связанные с шифрованием и расшифровкой данных, управлением ключами шифрования, их ротацией. А ещё при таком шифровании обеспечивается порядок сортировки, что делает невозможным ДИАПАЗОННОЕ СКАНИРОВАНИЕ по зашифрованным индексам.
Ещё один способ — шифрование файловой системы. Минус в том, что при монтировании зашифрованной системы необходимо вручную вводить секреты с помощью других средств, так как экземпляр базы данных к моменту монтирования ещё не запущен.
Объем ТДЭ
Объем ТДЭ:
Преимущества шифрования на уровне кластера:
Шифрование в масштабе всего кластера соответствует требованиям соответствия и ставит галочку в отношении TDE. Он также соответствует критериям шифрования данных в состоянии покоя, т. е. постоянных данных.
MySQL шифрует каждую страницу журнала повторов и журналов отмены с помощью специальных ключей, а не ключей, используемых для шифрования таблиц. Ключ шифрования хранится в заголовке первого файла журнала повтора/отмены в
зашифрованное состояние.https://www.postgresql.org/message-id/CAEze2WgK%3D8fBtY2CcCffqCrux4wKYFEiRVpkoPMMVaRjDq6Cpg%40mail.gmail.com
Использование симметричных ключей
Шифрование с симметричным ключом — это метод шифрования данных, в котором для шифрования и дешифрования данных используется один и тот же ключ. Это также известно как криптография с одним ключом или криптография с закрытым ключом. Любой, у кого есть доступ к ключу, может расшифровать данные, поэтому доступ к ключу должен быть ограничен.
—псевдокод
шифр = функция шифрования (открытый текст, ключ)
открытый текст = функция_дешифрования (шифр, ключ)
Примечание о терминологии: Криптография с симметричным ключом также известна как криптография с закрытым ключом. Криптография с асимметричным ключом (обсуждаемая позже) также известна как криптография с открытым ключом. Каждому открытому ключу соответствует секретный ключ. Во избежание путаницы в контексте данного руководства термин «закрытый ключ» используется только в контексте асимметричных ключей и как аналог соответствующего открытого ключа. Криптография с симметричным ключом называется только «криптографией с симметричным ключом», а не синонимом «криптография с закрытым ключом». Термины «криптография с асимметричным ключом» и «криптография с открытым ключом» используются как взаимозаменяемые.
Чтобы зашифровать данные с использованием шифрования с симметричным ключом, используйте функцию шифрования pgp_sym_encrypt():
—псевдокод
pgp_sym_encrypt(‘конфиденциальные данные для шифрования’, ‘symmetric_key’)
ВСТАВИТЬ пациентов (имя, примечания_симметрично)
ЦЕННОСТИ (
«Джейн Доу 1»,
pgp_sym_encrypt(
«У 66-летней женщины в течение последних 2 недель наблюдаются симптомы боли в нижних левых коренных зубах. Никаких проблем с зубами в анамнезе не было. Курю время от времени.’,
‘this_is_a_dummy_secret_key’
)
) ;
Вставьте еще одну строку:
ВСТАВИТЬ пациентов (имя, примечания_симметрично)
ЦЕННОСТИ (
«Джон Доу 1»,
pgp_sym_encrypt(
«66-летний мужчина жалуется на симптомы боли в нижней левой части живота в течение последних 2 недель. Никаких проблем с почками в анамнезе не было. Иногда пьет.’,
‘this_is_a_dummy_secret_key’
)
) ;
Взгляните на таблицу с зашифрованными данными:
ВЫБРАТЬ * ИЗ пациентов;
Данные в столбце «notes_symmetric» отображаются в виде зашифрованного текста.
Для расшифровки используйте функцию pgp_sym_decrypt() для зашифрованных данных:
—псевдокод
pgp_sym_decrypt(‘зашифрованные конфиденциальные данные’, ‘symmetric_key’)
Ключ, используемый для шифрования данных, также используется для расшифровки. Расшифруйте столбцы, содержащие зашифрованные данные:
ВЫБРАТЬ
имя,
pgp_sym_decrypt(
Notes_symmetric::BYTEA,
‘this_is_a_dummy_secret_key’
)
ОТ пациентов;
Чтобы выполнить запрос, основанный на фактическом (незашифрованном) значении зашифрованного столбца, используйте условие WHERE на расшифрованном значении столбца. Например, чтобы найти пациентов, в чьих записях упоминается слово курить:
ВЫБРАТЬ
имя,
pgp_sym_decrypt(
Notes_symmetric::BYTEA,
‘this_is_a_dummy_secret_key’
)
ОТ пациентов
ГДЕ
pgp_sym_decrypt(
Notes_symmetric::BYTEA,
‘this_is_a_dummy_secret_key’
) НРАВИТСЯ ‘%smoke%’ ;
Тип данных BYTEA
Обратите внимание, что в приведенных выше примерах зашифрованные данные приводятся к типу BYTEA. Этот тип данных используется для двоичных строк. Шифрование создает зашифрованный текст двоичных данных. Аналогичным образом расшифровка работает со строками двоичных данных. В этом руководстве столбцы, содержащие зашифрованные данные, имеют тип данных ТЕКСТ. Поэтому перед расшифровкой зашифрованные данные (в текстовом формате) преобразуются в двоичные.
Альтернативно вы также можете спроектировать таблицу так, чтобы столбцы зашифрованных данных имели тип BYTEA. Если тип столбца — BYTEA, функции дешифрования могут работать с ним напрямую, без приведения типов. Однако обратите внимание: если тип столбца — BYTEA, он может отображаться по-разному в зависимости от интерфейса. Например, программа терминала и программа с графическим интерфейсом могут отображать двоичное значение по-разному, в зависимости от настроенной кодировки программного обеспечения. Чтобы избежать этой потенциальной путаницы, в этом руководстве для зашифрованных данных используются столбцы ТЕКСТ.
Заключение
Выбор использования симметричных или асимметричных ключей зависит от целей безопасности, настройки инфраструктуры и организационной структуры. В целом, открытые ключи более безопасны, но они связаны с бременем управления закрытым ключом. Прежде чем принимать решение, оцените последствия каждого подхода для безопасности. На практике ключи часто являются частью кода приложения, осуществляющего доступ к базе данных. Следовательно, доступ к коду приложения, считывающему конфиденциальные данные, также необходимо ограничить. При использовании открытых ключей доступ WRITE предоставляется более широкой аудитории, а доступ READ ограничивается. При использовании симметричных ключей любой, у кого есть доступ ЗАПИСЬ, также имеет доступ ЧТЕНИЕ.
В документации pgcrypto также обсуждаются несколько дополнительных функций для шифрования столбцов и работы с двоичными данными. В частности, разберитесь в использовании функций pgp_sym_encrypt_bytea() и pgp_sym_decrypt_bytea(), а также pgp_pub_encrypt_bytea() и pgp_pub_decrypt_bytea().
Помимо шифрования столбцов, в документации PostgreSQL обсуждается несколько других вариантов шифрования. Важно не полагаться на одну меру безопасности, а вместо этого использовать несколько уровней безопасности. Последние версии PostgreSQL также поддерживают безопасность на уровне строк. В сочетании с безопасностью на уровне столбцов это приводит к еще более детальному подходу к безопасности данных.
IV для шифрования кучи/индекса
IV для кучи/индекса (в дополнение к требованиям XTS) пока не ясен. Вероятно, это будет смесь чего-то из этого:
IV для шифрования WAL
WAL может использовать режим CTR, поскольку CTR — это потоковый шифр, а повторное использование IV не является проблемой для WAL.
IV для временных файлов
Непонятно, как установить nonce для временных файлов. Мы, вероятно, будем использовать ключ шифрования данных, сгенерированный при запуске postmaster, и смешивать его с временем суток, идентификатором процесса и, возможно, путем к файлу.





