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


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

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

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

Владельцы файлов не контролируют, как выполняется шифрование в облачных сервисах, и кто имеет доступ к ключам для расшифровки. Поэтому утечки случаются с завидной регулярностью, и от них страдают даже крупнейшие компании. Например, в октябре 2020 года с серверов Nitro Software украли 1 ТБ конфиденциальных документов, принадлежавших Google, Apple, Microsoft и Citibank.

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

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

Поэтому мы взялись за разработку системы, в которой сочетались бы удобство современного облачного хранилища, end-to-end шифрование и принцип on-premise — возможность развернуть все на собственной инфраструктуре.

Особенности задачи

Особенность разработки криптографических систем в том, что здесь нет простора для творчества. Оно даже вредно. Нельзя просто взять и придумать новый протокол шифрования, его безопасность должна быть доказана многолетними независимыми исследованиями. И так во всем.

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

Хранилище Bastion Secure Cloud (BSC) 

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

Нюансы шифрования

Чтобы использовать e2e-шифрование и в то же время реализовать удобное управление доступом к файлам, пришлось уделить много внимания криптографии.

Мы использовали алгоритм AES256 GCM. С его помощью шифруется каждый файл в хранилище. Затем шифруется каждая папка, каждый каталог с файлами. При этом ключи шифрования хранятся рядом с зашифрованными файлами.

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

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

На вершине иерархии находится корневой каталог. Мастер ключ, который дает доступ к корневому каталогу и всему содержимому облака, хранится отдельно. Он зашифрован при помощи открытого ключа X25519.

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

Каждый файл шифруется перед загрузкой в BSC на компьютере пользователя при помощи свежего 256-битного симметричного ключа. Целостность данных обеспечивает Galois/Counter Mode — специальный режим работы алгоритма AES.

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

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

Следите за руками. Сейчас будет сложно.

Обмен файлами

Предположим, клиент должен безопасно передать нам в Бастион электронную копию договора.

Мы генерируем ссылку на загрузку файла при помощи веб-интерфейса облака. К ссылке автоматически добавляется «хвост» из случайной последовательности знаков. Часть этой последовательности выступает в роли идентификатора ID, а часть используется в качестве ключа A.

Приложение отсылает ID на сервер облака, а мы отправляем ссылку клиенту, например, через мессенджер. Вместе с ссылкой клиент получает доступ к клиентскому веб-приложению для загрузки файлов в облако, ID и ключ A.

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

Затем, веб-интерфейс использует ID для подключения к облаку, отправляет туда зашифрованный договор и получает публичный ключ C, созданный заранее на стороне Бастион.

Теперь клиентское приложение шифрует файл с ключом B при помощи ключа C. И тут же шифрует получившийся файл еще раз при помощи ключа A.

На нашей стороне эта матрешка расшифровывается в обратном порядке. Сперва ключом A, переданным по независимому каналу связи, затем секретным ключом C, который не покидал компьютер.

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

Шифрование в браузере

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

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

Браузер — прежде всего средство просмотра веб-страниц и выполнения несложной логики с ограниченным доступом к аппаратным средствам.

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

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

Если вкладка потребляет много оперативной памяти, браузер закрывает ее и перезапускает. Например, Safari ограничивает потребление вкладки примерно 4 ГБ. Это, не говоря о том, что оперативная память сама по себе сильно ограниченный ресурс. В средненьком ноутбуке установлено 8 ГБ, а необходимо обеспечить работу и с более тяжелыми файлами.

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

Мы проводили расшифровку файла в том же потоке, который отвечает за отрисовку страницы с веб-интерфейсом облака. Однако в браузерах используется Workers — механизм, который позволяет запускать скрипты в фоновом потоке, отдельно от страницы. Каждый Worker использует собственную память, и, как выяснилось, может использовать файл подкачки.

Переложив расшифровку на Worker, мы избавились от проблемы с ограниченным объемом ОЗУ и ускорили расшифровку, задействовав несколько ядер процессора. Даже веб-интерфейс стал отзывчивее, так как Worker работает асинхронно, независимо от вкладки, и не мешает браузеру обрабатывать страницу.

Что дальше

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

Bastion Secure Cloud можно пользоваться бесплатно, без ограничений на объем хранилища и доступные функции. Единственное условие — размер команды — до 10 зарегистрированных пользователей. Вы можете создавать публичные папки и с их помощью обмениваться файлами с незарегистрированными пользователями, так что это не такой жесткий лимит, как можно подумать.

Недавно мы полностью переработали интерфейс BSC, добавили мобильную верстку, управление правами на доступ к файлам и теперь занимаемся разработкой новых функций. Планируем реализовать создание и скачивание архивов, подобно тому, как это работает в Google Drive и Яндекс.Диск и готовим клиент для windows и linux-машин.

Делаем ставку на то, что компании станут внимательнее относиться к хранению данных, спрос на защищенные хранилища будет расти, и готовимся к этому

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


  1. Scratch
    16.03.2022 13:12

    25519 не умеет шифровать, это алгоритм Diffie-hellman. Вы используете самописный ECIES или может новый стандарт HPKE?


  1. ionicman
    16.03.2022 17:52

    Я не понял самого главного — как победили скачивание и расшифровку больших файлов-то?
    Мелкие да — можно в temporary FS положить, там расшифровать, потом отдать и удалить.

    Upload без проблем делается чанками и их можно шифровать на лету.

    А при download-е больших файлов сразу две проблемы — первая — как их расшифровывать на лету (ибо чанками нет способа их обрабатывать) и второе — как показать пользователю диалог сохранения такого файла?

    Т.е например я хочу скачать файл размером 50 мб и чтобы было показано обычное ркршко сохранения файла. В worker и его временную память это тоже не влезет. Как Вы такое делаете?


    1. SantrY Автор
      16.03.2022 19:44

      Скачивание по блокам тоже возможно, s3 поддерживает Range. Подробнее можно почитать здесь и здесь. Даже так Firefox и Safari могут дропнуть вкладку, но уже после 20-40гб. А вот в Chrome благодаря File System Access API так можно загружать загружать файлы неограниченного размера.

      Что касается отображения — процесс загрузки сначала показывается в UI облака, а затем, когда файл «собран» вызывается стандартный диалог сохранения. При этом скачивание не начинается заново, так как файл уже находится на диске во временных файлах системы.


      1. ionicman
        17.03.2022 08:28

        Range — это Вы имеете ввиду, что можно качать файл кусками, правильно?
        Да, я могу с помощью range запрашивать куски файла (но речь была про немножко другое), а где вы из собирать будете, если, например, файл длиной 500гб? Temp FS/local storage не даст это сделать по лимитам — 10Mb по-умолчанию.

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

        А асинхронно — типа открыть скачивание файла и пихать туда чанки, считанные через range не получится — нет такого API.


        1. Scratch
          18.03.2022 07:30

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


          1. ionicman
            18.03.2022 19:04

            Вот я как раз и хотел узнать так сказать из первых рук — как работают в таком режиме здесь, в том числе на мобильных браузерах.

            Но, видимо, мне не ответят.


  1. aborouhin
    16.03.2022 18:14

    End-to-end шифрование - это прекрасно, но вот применительно к корпоративному файловому хранилищу возникают большие вопросы:

    1. Полнотекстовым поиском по файловому хранилищу на сервере, я так понимаю, по понятным причинам пришлось пожертвовать? А это довольно важное требование, когда там скопленная за 10+ лет помойка на терабайты, которую разгрести невозможно, но вот что-то найти там периодически надо.

    2. Как решается вопрос восстановления пользовательских ключей (и зашифрованных ими данных) при их утрате? Ведь для этого ключи (пользовательские или резервные) всё равно в какой-то форме должны попадать на сервер (файловый или другой) - и преимущества end-to-end шифрования в существенной степени сводятся на нет?

    P.S. Я со своей стороны импортозаместил зарубежный сервер Seafile + Backblaze B2 (который тупо невозможно дальше оплачивать...) на тот же зарубежный сервер Seafile + S3QL + объектное хранилище Яндекс.Cloud. Яндексу (которому доверять, естественно, ни малейших оснований) попадают уже зашифрованные данные, бонусом S3QL даёт локальный кэш, дедупликация и сжатие. В случае полной потери доступа к зарубежному серверу (что, увы, не исключено) придётся поднять в другом месте только его (что быстро), а не копировать терабайты данных. Но шифрование не end-to-end, а на стороне сервера, в т.ч. по описанным выше причинам.


    1. SantrY Автор
      16.03.2022 20:02
      +1

      Просто наше решение немного другого класса, нежели то, что вам нужно. К сожалению, когда делаешь упор на безопасность, чем-то приходится жертвовать.

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

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


      1. aborouhin
        16.03.2022 20:09

        Ответы на вопросы ожидаемы (а как ещё-то с end-to-end), но вот сценарий применения Вашего решения по-прежнему не очень понятен. В корпоративном окружении рисковать потерей информации, если один-единственный сотрудник утопил ноут / уволился и послал всех по адресу / умер и т.п. - как-то это кажется куда как бóльшим риском для безопасности, чем потенциальный взлом сервера с ключами.


        1. Scratch
          16.03.2022 20:36

          Если в end-to-end больше чем два end-a, то он же всё равно end-to-end. Можно шифровать все ключи на "публичный ключ судного дня", доступ к которому есть только у начальства


  1. connected201
    17.03.2022 00:04

    Kласно, будем пробовать, и тут первый вопрос, почему это выскакивает? хотел открыть по вашей ссылке pdf файл.
    Kласно, будем пробовать, и тут первый вопрос, почему это выскакивает? хотел открыть по вашей ссылке pdf файл.


    1. SantrY Автор
      17.03.2022 10:23

      Превью pdf открывается в iframe, так что блокировщики рекламы его иногда обрезают.


  1. acmnu
    17.03.2022 14:49

    Не рассматривали вариант с "прокси" на стороне клиента, которое занимается расшифровкой?


  1. solarplexus
    18.03.2022 13:06

    Для чего идет шифровка зашифрованного ключа ключом A? Какой смысл несет данная операция?