Привет, Хабр!

Как мы знаем, защита конфиденциальной информации — это неотъемлемая часть любого проекта. В статье поговорим про шифрование данных в PostgreSQL, а именно про шифрование с использованием как асимметричных, так и симметричных ключей.

Немного про асимметричное и симметричное шифрование

Асимметричное шифрование использует пару ключей для шифрования и расшифрования данных: открытый и закрытый ключи.

  • Открытый ключ: используется для шифрования данных и доступен всем пользователям.

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

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

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

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

Шифрование симметричными ключами в PostgreSQL

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

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

-- создание симметричного ключа
CREATE EXTENSION IF NOT EXISTS pgcrypto;

-- генерация симметричного ключа
SELECT gen_random_bytes(16) AS symmetric_key;

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

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

-- шифрование данных с использованием симметричного ключа
SELECT pgp_sym_encrypt('Secret message', 'AES_KEY');

-- дешифрование данных с использованием симметричного ключа
SELECT pgp_sym_decrypt('Encrypted message', 'AES_KEY');

Шифруем сообщение "Secret message" с использованием симметричного ключа AES_KEY, а затем дешифруем его обратно.

Например, нужно хранить конфиденциальную информацию о юзерах в БД, например, их пароли:

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50),
    encrypted_password TEXT
);

-- вставка данных с зашифрованным паролем
INSERT INTO users (username, encrypted_password)
VALUES ('user1', pgp_sym_encrypt('password123', 'AES_KEY'));

При вставке нового пользователя мы шифруем его пароль с помощью симметричного ключа AES_KEY.

Шифрование асимметричными ключами в PostgreSQL

Первый шаг в таком шифрование - создание пары ключей: открытого и закрытого.

Для генерации пары ключей в PostgreSQL можно использовать функцию pgcrypto.gen_rsa_keypair, которая создает пару ключей RSA:

-- создание пары ключей RSA
SELECT pgp_pub_encrypt('Super secret data', rsa_pub) AS encrypted_data
FROM (SELECT pgcrypto.gen_rsa_keypair(2048) AS rsa_pub) AS keys;

Запрос создает новую пару ключей RSA и шифрует строку Super secret data с использованием открытого ключа.

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

SELECT pgp_pub_encrypt('Super secret data', rsa_pub) AS encrypted_data
FROM (SELECT '-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: PGP ..

mQENBE+zv4UBCAC2Xljsn1FTmLX2zW/KG1QVpukDtJZIKAFZlCz8PrQkg/hfpxiH
d4dgbUzVWg3Ew0yGmLoImf+PQK7Cf5Nvl5feoX9P9pUJ4FZfSYBF5FjS2zlbjcG+
q2K1L9zP7vIlpZ5OYd9r3HyLhKThyP2g95DWf9INtC7nFpT8Uw9+7HK20W/buyPj
...
-----END PGP PUBLIC KEY BLOCK-----' AS rsa_pub) AS keys;

Запрос шифрует строку "Super secret data" с использованием открытого ключа RSA.

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

SELECT pgp_priv_decrypt(encrypted_data, rsa_priv) AS decrypted_data
FROM (SELECT pgp_pub_encrypt('Super secret data', rsa_pub) AS encrypted_data,
             pgcrypto.gen_rsa_keypair(2048) AS rsa_priv) AS keys;

Этот запрос шифрует строку "Super secret data" с использованием открытого ключа RSA, а затем расшифровывает ее с использованием соответствующего закрытого ключа.

К примеру нужно обеспечить безопасную передачу конфиденциальной информации между двумя юзерами:

CREATE TABLE encrypted_messages (
    id SERIAL PRIMARY KEY,
    sender_username VARCHAR(50),
    recipient_username VARCHAR(50),
    encrypted_data TEXT
);

-- шифрование и сохранение сообщения для отправителя
INSERT INTO encrypted_messages (sender_username, recipient_username, encrypted_data)
VALUES ('sender', 'recipient', pgp_pub_encrypt('Secret message', rsa_pub));

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

Сравнение

Критерий

Асимметричные ключи

Симметричные ключи

Тип ключа

Два различных ключа: публичный и приватный

Один общий ключ для шифрования и дешифрования

Безопасность

Высокая

Высокая, но в целом меньше, чем у асимметричных ключей

Управление ключами

Посложней

Попроще

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

Обычно медленнее

Обычно быстрее из-за одного общего ключа

Подпись и шифрование

Могут использоваться как для подписи, так и для шифрования данных

Используются только для шифрования данных


Итак, используйте асимметричные ключи, когда требуется обмен данными между различными системами или юзерами, и когда необходимо обеспечить большую степень безопасности за счет публичного/приватного ключа. А вот в случаях, когда данные хранятся и обрабатываются в рамках одной системы или приложения, симметричные ключи могут быть предпочтительны из-за их проще управляемости и более высокой производительности.

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

Комментарии (3)


  1. mr-giz
    28.04.2024 17:57

    Здесь прекрасно всё. И ключ в шестнадцать байт и хранение зашифрованных, а не хешированных паролей. RSA на какой либе кстати? На мой взгляд БД должна хранить информацию и обеспечивать ACID и прочие плюшки БД. А всё остальное должно выполняться прикладом. Нет, я конечно видел здесь и статью где из постгреса почтовые рассылки отправляли. Можно конечно, но каждому инструменту - своё место, имхо.


    1. gudvinr
      28.04.2024 17:57
      +2

      А всё остальное должно выполняться прикладом

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

      Нужно ли UUID формировать на стороне SQL клиента и в БД хранить блоб (как вы бы это делали в sqlite) или можно/нужно пользоваться встроенными типами?

      А кастомные типы, которые хранят сеты?

      А jsonb, который умеет в индексы по полям JSON?

      И т.д.

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

      Где эта грань, когда заканчиваются "плюшки бд" и начинается прикладной софт?


    1. breninsul
      28.04.2024 17:57

      ну pgcrypto полезный модуль, и шифрование может пригодиться, просто пример с паролем не удачный. Может подойти sharedKey от otp.