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

Какой ещё секрет?

Секрет – это конфиденциальная строка текста, которая даёт прямой или косвенный доступ к информационным ресурсам. Например, строка подключения к базе данных (БД), которая даёт доступ к информации в БД.

Что вы получите от статьи?

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

Зачем это нужно?

У компании, в которой я проходил практику, есть около 60 веб-сервисов и приложений, которые продолжают улучшаться и поддерживаться. У каждого сервиса есть в среднем около 15-20 секретов, например: логин и пароль от админки, API-ключи, строки подключения к БД, ключи шифрования и т.д. Обычно они хранятся в специальных файлах конфигурации проекта (appsettings.json) либо прямо в коде, а у продвинутых может храниться в Secret Manager. Управлять ими в таком формате, когда они разбросаны по разным репозиториям и файлам, проблематично. Под "управлять" я имею в виду такие действия, как получение и периодическое обновление секретов. Передаются эти секреты между разработчиками обычно через мессенджеры, что приводит к их расползанию.

Что бы сдать этот диплом решить эти проблемы, я сделал свой сервис для управления секретами.

Да похожие системы уже давно существуют, например, HashiCorp Vault и Passwork. Но эта статья не про них. Однако коротко скажу, почему я не использовал их:

  1. «Сложно» настраивать или дорого покупать.

  2. Диплом с готовым решением вряд ли защитил бы.

  3. Хотел попробовать изобрести свой велосипед, сделанный на стеке компании: C#, ASP.NET, Angular.

Что требуется от системы?

Разумеется, не будем реализовывать весь функционал из существующих сервисов. У меня не было ни времени, ни ресурсов для этого. Моя цель была с минимальными усилиями сдать диплом на максимальный результат, что в итоге и получилось.

Вот что мы будем реализовывать:

  1. Передачу данных между клиентом и сервером в зашифрованном виде с использованием асимметричного шифрования (RSA).

  2. Хранение данных в зашифрованном виде, чтобы компрометация БД не приводила к компрометации всех секретов. Для этого будем дополнительно использовать симметричное шифрование (AES).

  3. Надёжное распределение и передача секретов пользователям и системам.

Как будем реализовывать?

Используем такой стек: C#, ASP.NET, Angular с TypeScript. Рассмотрим, как безопасно передавать информацию от клиента к серверу.

Во-первых, перед отправкой нужно шифровать данные. Мы можем использовать симметричное шифрование, когда для шифрования и расшифровки используется один ключ, либо асимметричное шифрование, когда для шифрования и расшифровки используются разные ключи. Объясню, почему мы не можем использовать симметричное шифрование. Допустим, мы на клиенте сгенерировали ключ, с помощью этого ключа зашифровали данные и отправили этот шифр на сервер. Злоумышленник не сможет расшифровать его без ключа клиента, но и сервер не сможет его расшифровать для отправки другим клиентам. Если отправлять и ключ, то смысла от шифрования не будет. Поэтому выбираем асимметричное шифрование.

Для расшифровки секретов серверу нужны ключи. Они будут храниться в таблице «Safe». Каждый секрет относится к какому-то сейфу. Сейф имеет два ключа – публичный и приватный. Приватный ключ перед сохранением в БД шифруется с помощью симметричного алгоритма, а ключ от него хранится на сервере (не в БД).

Чтобы получить доступ к секрету, нужно иметь соответствующие разрешения и нужный ключ для «открытия» сейфа. Название проекта – Bank of Secrets (BOS) – аналогия с банком, безопасность и надежность.

Схема взаимодействия клиента и сервера

Предварительные действия перед отправкой секрета на сервер:

  • Клиент отправляет запрос на создание сейфа.

  • Сервер создаёт сейф и генерирует два ключа (приватный и публичный). Перед сохранением в БД приватный ключ шифруется с помощью AES. Пример кода:

    //endpoint: api/safe/create
    var keys = asymmetricCrypto.GenerateKeys();
    string PublicKeyPem = keys.publicKeyPem;
    string PrivateKeyPem = keys.privateKeyPem;
    // Encrypt private key before saving
    string EPrivateKeyPem = cryptorService.EncryptWithSecretKey(PrivateKeyPem);
    // save keys

    Метод EncryptWithSecretKey использует ключ из конфигурации проекта (appsettings.json) и методы из пространства имён System.Security.Cryptographyи получает шифр для ключа.

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

Создание и отправка секрета на сервер

Процесс создание секрета
Cоздание секрета
  1. Клиент получает публичный ключ из сейфа.

  2. Шифрует введённые данные с помощью асимметричного шифрования.

  3. Хэширует шифр и асимметрично шифрует его с помощью публичного ключа (формируется цифровая подпись).

  4. Шифр + хэш шифра (подпись) + публичный ключ (для проверки подписи) отправляются на сервер.

  5. Сервер проверяет подпись и сохраняет секрет в БД точно в том же виде, как он пришёл на сервер.

Получение секрета на клиенте

Получение секрета
Получение секрета
  1. Клиент формирует пару RSA ключей, прикрепляет к запросу публичный ключ и отправляет запрос на получение секрета.

  2. Сервер проверяет все разрешения пользователя.

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

  4. Полученный шифр отправляется клиенту.

  5. Клиент расшифровывает его с помощью своего приватного ключа.

Такой подход обеспечивает отправку и получение записи в зашифрованном виде, гарантируя, что никто, кроме сервера и клиента, не сможет её расшифровать, даже в случае перехвата запроса или трафика. Благодаря цифровой подписи, данные защищены от атак типа «человек посередине» (MITM) и подмены информации. Комбинирование асимметричного и симметричного шифрования защищает нас от компрометации базы данных: даже если злоумышленники получат доступ к БД, они не смогут воспользоваться этими данными.

Что следует учитывать?

  • Риски, связанные с централизацией секретов. Ну, сами подумайте: все ваши секреты хранятся на одном сервере, компрометация которого приведёт к компрометации всей IT-инфраструктуры компании. Надёжные бэкапы и жёсткая политика безопасности данного сервиса, возможно, помогут вам.

  • Существует государственные стандарты по реализации таких систем. Разобраться в этих ГОСТах бывает непросто, так как они написаны языком, понятным преимущественно математикам. В них указаны требования к размерам ключей и другим математическим параметрам. Поэтому, если вам предстоит работать с криптографией в государственном секторе, важно учитывать эти ГОСТы.

  • Как оказалось, для использования криптографических алгоритмов необходимо получить сертификат от ФСБ. Они не хотят просто наблюдать за тем, как вы обмениваетесь непонятными символами, они хотят знать всё. Вероятно, от вас потребуют предоставить все ключи, чтобы при необходимости иметь возможность расшифровать любое ваше сообщение.

  • Формирование парных ключей для каждого запроса и использование асимметричного метода шифрования данных - считается плохой практикой. Лучше использовать асимметричное шифрование только для формирования общего симметричного ключа, так как симметричное шифрование работает значительно быстрее. Это особенно важно, если объём данных большой.

  • Обратите большое внимание на формат ключей, они бывают разных видов. Если вы создаёте ключи на клиенте в PEM формате, а на сервере для алгоритма используется PKCS 8 формат, то у вас будет ошибка.

Заключение

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

Телеграм: https://t.me/khayka

Описание и исходный код проекта

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


  1. MAXH0
    29.06.2024 10:52
    +5

    Нв Хабре была эпидемия "курсовых" по криптографии. Теперь нам стоит ожидать такой же эпидемии дипломных проектов?


    1. 0xC0CAC01A
      29.06.2024 10:52
      +3

      А потом ещё и эпидемии новых соискателей на ИБ-шном рынке труда ))


      1. MAXH0
        29.06.2024 10:52
        +1

        Главное чтобы по факту все эти статьи не были от соискателей на должность контент менеджера...


  1. Vasjen
    29.06.2024 10:52
    +1

    Обычно они хранятся в специальных файлах конфигурации проекта (appsettings.json) либо прямо в коде.

    Я думал, так только индусы с Ютуба делают. Для чувствительных данных есть секреты.


    1. Khay_Darov Автор
      29.06.2024 10:52

      Да тихо ты (статью обновил)


  1. Thomas_Hanniball
    29.06.2024 10:52

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

    Теперь понятно, почему в статье столько "воды" в начале.


    1. Khay_Darov Автор
      29.06.2024 10:52

      Да это не вода, так... конденсат максимум


  1. Kahelman
    29.06.2024 10:52
    +1

    “Сервер создаёт сейф и генерирует два ключа (приватный и публичный). Перед сохранением в БД приватный ключ шифруется с помощью AES”

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

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

    Публичные ключи храниться на центральном сервере для простоты поиска/обновления,

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

    Как раздавать авторизацию( регистрировать публичные ключи- дело десятое, хоть в app.settings” храните.

    поздравляю вы переизбрали OpenPGP :)


    1. Khay_Darov Автор
      29.06.2024 10:52


      С понятием OpenPGP почему то во время поиска не сталкивался, спасибо, буду знать.

      А ключи АЕS шифрования вы где хранить будете?

      В моей реализации ключ храниться в appsettings.json. Для компрометации секретов потребуется: знать ключ от приложения из (appsettings.json\env) + шифр из БД.

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

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

      PS: Кстати, во время защиты комиссия также отметила этот момент :) посоветовала рассмотреть возможность распределённого хранения данных вместо централизации


      1. Kahelman
        29.06.2024 10:52

        Если у вас есть доступ к appsetting файлу то у вас есть доступ к БД.

        Проблема обмена открытыми ключами решена в openssh. Просто шлете публичный ключ на сервер.

        Секреты не нужны - используйте public/private key шифрование.


  1. BaJIepoH
    29.06.2024 10:52

    Подключили ldap к passwork в свое время, админа переназначить не смогли - пароль его почему-то не проходил. Подключились к монге на тачке и поменяли ему айдишник на админовский. После этого компания отказалась от дальнейшего использования пассворка, но при этом подготовили все для переезда из 1pass. И ладно бы он развивался..дизайн придумали другой, либо полей накинули..