Bollywood HungamaMahakavya Shri Ramayan Katha producer Prakash Mahobiya alleges ‘negative marketing’; hints at big-budget Ramayana saying, “We never got a chance to reach our audience”Punch2027: Nigeria on path to renewed greatness under Tinubu — APC chieftainESPNTransfer rumors, news: Man United, Arsenal, Chelsea battle for Freiburg strikerThe Jerusalem PostSuspected criminal assassination attempt leaves two wounded after car explosion, fire in JerusalemCNN Türkİsmail Kartal'dan, Greenwood'a: Sinirlerine hakim olDaily MaverickIN PICTURES: Bensonvale College — a fading monument to generations of teachersInquirerDepEd expands program to empower parents as co-educatorsSouth China Morning PostSoutheast Asia urged to step up war against AI-powered scams through data sharing3DNewsДорогое топливо поменяло авторынок: электромобили и гибриды впервые захватили больше 50 % мирового рынка новых машинIl Fatto QuotidianoDdl antisemitismo, contrarie anche le organizzazioni ebraiche: “Rischia di censurare le critiche a Israele e di creare dei ghetti legislativi”ZDF heuteAktuelle Pressemitteilungen des ZDFCapital FMNyoro gives Ruto 14 days to disclose Dangote refinery deal
The Daily Newsstand · Free, Always
Tuesday, October 6, 2026

Как я делаю защищенное файловое хранилище — 2: Ограничения и возможности

Translate

Армянский язык очень своеобразный. Прожив несколько лет в Армении, я могу безошибочно отличить его на слух от любого другого незнакомого языка. Кстати, вы знали, что в фильме «Борат» друг Бората говорит не на казахском, а на армянском?

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

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

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

Вот так, перемещаясь время от времени по городу и размышляя по дороге, я и продолжил работать над своим проектом.

2. Чего же мы хотим?

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

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

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

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

Надо сказать, контейнеризация сильно упрощала мне жизнь. Базовая структура будущего приложения тут же сложилась сама собой:

             .
Docker       .       Docker
container    .       volumes
┌──────┐     .     ┌───────────┐
│      │     .     │ Encrypted │
│      │     .     │ files     │
│ App  │     .     └───────────┘
│ core │     .     ┌───────────┐
│      │     .     │ Encrypted │
│      │     .     │ key       │
└──────┘     .     └───────────┘
             . 

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

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

Кроме того, контейнеризация позволяла разделить весь проект на независимые сервисы. Ядро приложения, клиентская часть, тесты и прочее — все могло жить в собственных контейнерах, со своими зависимостями:

               .                  .
┌──────────┐   .   ┌──────────┐   .   ┌──────────┐
│ Core     │   .   │ Client   │   .   │ Extra    │
│ app      │   .   │ app      │   .   │ servcies │
└──────────┘   .   └──────────┘   .   └──────────┘
               .                  . 

Ядро приложения должно выставлять наружу только API. Тогда можно подключать к нему любые клиенты. Их можно свободно менять или комбинировать, не трогая основную логику хранилища. Или работать с приложением напрямую через API вообще без клиентов (например, встроив его в какую-нибудь другую систему).

В качестве бонуса API решал еще одну важную задачу: при атаке по локальной сети поверхность атаки сужалась до одного интерфейса. Никаких SMB, NFS или других характерных файловых протоколов.

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

3. Нужные вещи

Идея постепенно превращалась в список вполне конкретных требований:

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

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

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

  4. Простота использования. Пользователь не должен думать о криптографии. Он должен просто работать с файлами. Шифрование должно оставаться внутренней задачей приложения.

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

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

  7. Dead Man’s Switch. Я все еще не знал, как именно должен работать этот механизм, но было понятно, что без него вся концепция теряет смысл. В списке требований он занял отдельное место.

Тут я всерьез задумался: а нужно ли вообще кому-то такое приложение? Прежде всего мне самому. Я решил провести простой мысленный эксперимент.

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

И дело вовсе не в содержимом фотографий. Дело в том, что они только мои.

Можно было двигаться дальше.

4. Так что же это?

Так постепенно складывался образ будущего приложения. Я уже представлял, как оно должно работать. И как оно работать не должно.

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

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

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

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

Можно было переходить к выбору технологий.

5. Язык

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

Сначала нужно было ответить всего на один вопрос: компилируемый или интерпретируемый? Производительность против простоты. Скорость выполнения против скорости разработки.

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

Как можно говорить о безопасности, если нельзя проверить, что в данный момент делает запущенное приложение?

Я мысленно вычеркнул все, что компилировалось. Выбор сузился вдвое и я стал перебирать оставшееся:

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

JS мне просто не нравился. Заставлять себя писать на языке, который мне не нравится, я не собирался.

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

Остался старый добрый Python. Годы развития, огромная экосистема, отличная документация, огромное сообщество. Но он был невероятно скучным: ни революций, ни постоянной смены парадигм, ни гонки за трендами. То, что надо!

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

6. Фреймворк

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

Django отпал первым. Он предлагал гораздо больше, чем мне было нужно, и выглядел слишком тяжелым для небольшого автономного приложения. Кроме того, мне не нравилось, что он слишком много делает за меня.

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

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

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

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

7. Конец второй части

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

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.