Всем привет! Мы - команда $mol_team, и нам есть что рассказать про безопасность. Недавно мы участвовали в хакатоне по кибериммунитету Касперского, от которого у нас остался любопытный артефакт, который будет небезынтересен всем, кого волнуют безопасные высоко доступные децентрализованные криптосистемы реального времени.  Создание программы для авторизованного управления оборудованием на теплоэлектростанции, поддерживающей обновление ПО с контролем лицензии.  По условиям организаторов в соответствии с кибериммунным подходом должна использоваться микросервисная архитектура на основе шины обмена сообщениями со встроенным монитором безопасности.  Дорогостоящее оборудование должно надёжно управляться только ответственным за него специалистами на основе правдивой и своевременной информации о его состоянии через сертифицированное лицензионное ПО.  В соответствии с принципом нулевого доверия, используется криптография для алгоритмического обеспечения целей безопасности на каждом узле системы.  Бизнес ценности, которые мы должны сохранять:  👀 Оператор видит корректную информацию о состоянии оборудовании в реальном времени, иначе может принять неверное решение, которое может привести к порче оборудования.  🛂 Только авторизованный оператор может управлять оборудованием в соответствии с ролевой моделью. Человек без подготовки или полномочий может навредить работе системы.  🧗‍♂️ Система выполняет свою функцию даже при выходе из строя или компрометации любого одного компонента системы. Поведение неуправляемой системы может быть сколь угодно плачевным.  👨‍💻 Запущенное ПО аутентифицировано его поставщиком, ответственным за обеспечение остальных целей, и предоставляющим обновления "на лету".  🎫 При истёкшем сроке лицензии, ПО продолжает работу, но его обновление не происходит.  🎁 Действия пользователей системы в периметре заказчика не может привести к утечке ключевого ПО.  Условия, которые должны быть обеспечены иными способами, чтобы наша система выполняла цели безопасности:   Оператор благонадёжен и ответственно выполняет все предназначенные для него регламенты, но как человек он может непреднамеренно ошибиться.   Каждый пользователь системы работает только под своей учётной записью.   В оборудовании, ОС и нашем собственном коде, нет закладок, но могут быть ошибки.   На каждом узле есть не доступное из вне хранилище ключей.   Технологическое оборудование исправно.   Пользователи имеют лишь удалённый доступ к системе управления.   Как мы защищаемся от различных нештатных ситуаций:   🔥 Событие   🚧 Защита   Сигнал изменён   Цифровая подпись   Автор сигнала не имеет прав   Криптоавторизация   Сигнал не доставлен   Протокол синхронизации   Дублирование промежуточных узлов   Сигнал не обработан   Реакция не на события, а на разницу состояний   Дребезг управления при быстрой смене сигналов   Реакция не на события, а на разницу состояний   ПО изменено не вендором   Цифровая подпись на стороне вендора   Криптоавторизация   Утечка ПО через пользователя   Шифрация секретным ключом на стороне вендра   Расшифровка непосредственно в обновляемом процессе   Обновление ПО по истечении срока лицензии   Криптоавторизация   Проверка срока при установке   Подделка лицензии   Криптоавторизация   Криптопривязка лицензии к конкретным девайсам  Выдаёт версию ПО.  Выдаёт статус активности.  Выдаёт статус обновления.  Мониторит обновления своего ПО и лицензии.  Проверяет лицензию и применяет обновление.  Выдаёт сырое значение показателя.  Показатель может требовать предварительной обработки:  Агрегация: среднее значение за определённое время.  Фильтрация: удаление не естественных всплесков.  power_sensor - вырабатываемая мощность, текущее значение с фильтрацией.  temp_sensor - температура воздуха, текущее значение с фильтрацией.  freq_sensor - частота вращения турбины, агрегирует сигналы за минуту.  Слушает управляющий сигнал.  Выдаёт статус текущего действия.  power_driver - вырабатываемая мощность.  main_driver - запуск/останов турбины.   Роль   Права и обязанности   Периметр   👼 Наблюдатель   Мониторит состояние системы.   ТЭЦ   👨 Оператор   Наблюдает за оборудованием и управляет им.   ТЭЦ   🧔 Инженер   Обновляет ПО и лицензии.   ТЭЦ   🤴 Админ   Настраивает политики безопасности.   ТЭЦ   🎅 Вендор   Предоставляет лицензии и ПО.   Офис вендора    Устойчивая: Все узлы минимум продублированы.  Крипрографическая: Все узлы объединены в единую одноранговую криптосеть.  Реплицированная: Все данные продублированы в распределённой БД между всеми заинтересованными узлами.  Реактивная: Прикладной код реагирует на изменение состояния БД, а не на события.  Доверенная: Вся информация аутентифицирована на входном узле.  Децентрализованная: Каждый узел независимо проверяет аутентификацию и авторизацию и общается напрямую лишь с одним девайсом (сенсором, драйвером, БД, пользователем и тд).  Свой протокол синхронизации - не нужны внешние сервисы типа Message Queue.  Только свой код - не нужны сторонние зависимости из node_modules.  Алгоритмический контроль доступа - не нужен централизованный аудитор запросов.  Узлы не знают друг о друге, а взаимодействуют только с базой данных CROWDs, которая автоматически синхронизируется между узлами.  Входные сигналы проверяются в экшенах, подписываются цифровой подписью, и вносятся в систему.  Драйвер CROWDs отвергает любые неавторизованные или нецелостные юниты информации, получаемые как из внешних систем, так и из локальной базы данных.  В изолированном периметре узла либо нет стороннего кода, либо он минимален.  Даже если скомпрометированный узел внёс в свою базу неавторизованные изменения, другие узлы откажутся с ним синхронизироваться.  Задачи мониторят изменение состояния в реальном времени и отражают эти изменения на других состояниях или на подконтрольных системах.  Реактивная архитектура с синхронизацией состояния проще и надёжнее событийной.  Затруднительно обеспечивать доверие стороннему сервису.  Узел, выступающий в рол сервера синхронизации, уже является аналогом брокера сообщений, так как связывает все узлы системы и гарантирует доставку всех изменений БД.  Отдельный брокер сообщений требует отдельные доверенные механизмы обновления и конфигурирования.  Обход или компрометация монитора безопасности делает систему полностью беззащитной.  Сервер синхронизации уже является аналогом централизованного монитора безопасности, так как проверяет аутентификацию и авторизацию всех проходящих через него юнитов информации.  Драйвер CROWDs уже является мини-монитором безопасности, стоящим перед каждым узлом.  Отдельный монитор безопасности требует отдельные доверенные механизмы обновления и конфигурирования.  Легенда: ✅ Желательно, ⭕ Бонус   Название   Назначение   Комментарий   Скоуп хакатона   Sync  Поддержание связности узлов для синхронизации БД в реальном времени.   Предотвращение распространения неавторизованных юнитов информации по сети.   Несколько экземпляров на разных физических устройствах.   ⭕   Persister   Резервирование состояния БД в ПЗУ.   Несколько экземпляров на разных физических устройствах.   ⭕   Temp Sensor   Управление датчиком температуры воздуха.   Приём от него показаний.   Внесение показаний в БД.   На каждый датчик - отдельный экземпляр Sensor.   ✅   Freq Sensor   Управление датчиком скорости вращения турбины.   Снятие с него показаний.   Предварительная их обработка.   Внесение обработанных показаний в БД.   На каждый датчик - отдельный экземпляр Sensor.   ✅   Power Sensor   Управление датчиком выходной мощности турбины.   Снятие с него показаний.   Внесение показаний в БД.   На каждый датчик - отдельный экземпляр Sensor.   ✅   Power Driver   Подача сигналов на устройство управления турбиной в соответствии с актуальными установками оператора.   Внесение в БД статуса своей работы.   На каждую турбину - отдельный экземпляр Driver.   ✅   Defender   Мониторинг критических показателей.   Автономная автоматизация реакции на нештатные ситуации.   Внесение в БД статуса своей работы.   На каждое защитное устройство - отдельный экземпляр Defender.   ⭕   HMI   Отображение авторизованному пользователю аутентифицированного состояния турбины.   Аутентификация и внесение в БД команд оператора.   Загрузка инженером обновлений ПО и лицензий.   Встраивается прямо в АРМ.   ⭕   Название   Назначение   DAC   Управление оборудованием.   ADC   Замер показателей оборудования.   WS   Работа с WebSocket соединениями.   Sync   Синхронизация БД   PG   Коммуникация с PostgreSql   PostgreSql   Хранение юнитов.   Выборка юнитов.   Гарантия целостности хранилища.   IndexedDb   Хранение юнитов.   Выборка юнитов.   Гарантия целостности хранилища.   DB.D   Хранение юнитов.   Выборка юнитов.   Гарантия целостности хранилища.   User   Выполнение должностных обязанностей через АРМ.   Название   Назначение   CROWD   Управление юнитами информации.   Аутентификация и авторизация юнитов.   Название   Назначение   NodeJS   Исполнение ПО в виртуальной машине.   Browser   Отображение аутентичных данных пользователю.   Приём управляющих сигналов от пользователя.   Domain   Работа с БД в терминах предметной области.   Installer   Отслеживание появления обновлений в БД.   Проверка сроков лицензии.   Расшифровка нового код.   Выгрузка кода в ФС.   Завершение работы контроллера для автоперезапуска с новым кодом.   File System   Хранение исполняющегося ПО.   Tasks   Отслеживание состояния БД.   Прямое воздействие на подконтрольные управляющие устройства.   Actions   Приём показаний от сенсоров.   Фильтрация и агрегация показаний.   Упаковка показаний в аутентичные юниты.   Внесение юнитов в БД.  I - идеальное решение, если у нас будут все необходимые ресурсы на разработку инноваций.  P - проектное решение, которое мы готовы реализовать с текущими технологиями.  H - упрощённое решение запланированное на хакатон.  Далее представлены общие схемы узлов. В зависимости от типа устройства, некоторые компоненты могут отсутствовать.  Полностью отказываемся от внешних зависимостей.  Выносим код синхронизации БД в отдельный процесс.  Пишем свой код работы с сокетами и исполняем его в отдельном процессе.  Пишем свою СУБД на компилируемом языке, оптимизированную для работы с CROWDs.  Датчики, управляющие устройства, защитные устройства и тд.    Обеспечивает связность узлов и гарантию доставки, попутно проверяя аутентификацию и авторизацию.    Бэкапит состояние БД в постоянное хранилище.    Аутентифицирует действия пользователя и отображает только аутентичные данные из системы.     Выделяем код общения со внешним миром и все сторонние зависимости в отдельный процесс виртуальной машины.   Используем PostgreSQL для постоянного хранения БД.  Датчики, управляющие устройства, защитные устройства и тд.    Обеспечивает связность узлов и гарантию доставки, попутно проверяя аутентификацию и авторизацию.    Бэкапит состояние БД в постоянное хранилище.    Аутентифицирует действия пользователя и отображает только аутентичные данные из системы.    Запускаем весь код в одном процессе виртуальной машины.  Датчики, управляющие устройства, защитные устройства и тд.    Обеспечивает связность узлов и гарантию доставки, попутно проверяя аутентификацию и авторизацию.    Бэкапит состояние БД в постоянное хранилище.    Аутентифицирует действия пользователя и отображает только аутентичные данные из системы.    В пакете может быть как зашифрованный код ПО, так и сроки лицензии. Если сроки не истекли и одновременно в БД есть свежее обновление, то оно устанавливается автоматически.    Обновление ПО сохраняется в БД, но не устанавливается, пока лицензия не будет продлена.    Обновления ПО и лицензии с нарушенной целостностью отвергаются сразу и не попадают в систему.    Установки оператора проверяются минимум на 2 узлах, к которым у него нет прямого доступа. Состояние турбины может вносить в БД только её драйвер. Оператор видит гарантированно аутентичный статус турбины и время последнего обновления статуса.    Состояние датчика может вносить в БД только его драйвер. Оператор видит гарантированно аутентичные показатели и время последнего их обновления.     Описание проблемы   Уязвимое место   Нарушенная цель   Стратегия снижения опасности   Скомпрометированный сенсор пишет в БД не корректные данные.   Sensor   1 👀   Расхождение показаний с дублирующими сенсорами может помочь выявить проблему.   Скомпрометированный драйвер подаёт некорректные сигналы на устройство.   Driver   3 🧗‍♂️   Сигналы с сенсоров позволят выявить проблему.     Скомпрометированный драйвер не пропускает сигналы управления устройством.   Driver   3 🧗‍♂️   Управляющий сигнал дойдёт через дублирующий драйвер.   Установщик не проверяет истечение срока лицензии.   Controller   5 🎫   Сценарий должен проверяться автотестами.   Описание проблемы   Уязвимое место   Нарушенная цель   Стратегия снижения опасности   Ошибка в сетевой библиотеке нарушает протокол синхронизации, что приводит к исключению узла из пиринговой сети.   WS   3 🧗‍♂️   Обновление ПО на новую версию библиотеки сперва проводится на менее важных узлах.   Ошибка в библиотеке синхронизации БД нарушает протокол синхронизации, что приводит к исключению узла из пиринговой сети.   Sync   3 🧗‍♂️   Обновление ПО на новую версию библиотеки сперва проводится на менее важных узлах.  Дополнительно к идеальному:   Описание проблемы   Уязвимое место   Нарушенная цель   Стратегия снижения опасности   Скомпрометированная сетевая библиотека нарушает протокол синхронизации, что приводит к исключению узла из пиринговой сети.   WS   3 🧗‍♂️   Обновление ПО на новую версию библиотеки сперва проводится на менее важных узлах.  Дополнительно к проектному:   Описание проблемы   Уязвимое место   Нарушенная цель   Стратегия снижения опасности   Скомпрометированная сетевая библиотека обходит встроенный монитор безопасности (CROWD) и напрямую управляет устройствами.   WS   2 🛂   —   Скомпрометированная сетевая библиотека обходит встроенный монитор безопасности (CROWD) и вносит в БД некорректные данные.   WS   1 👀   —    Вся база данных (world) делится на кластеры (land). Каждый ленд помимо данных содержит всю необходимую для аутентификации и авторизации информацию, и синхроизируется атомарно.  Каждый участник системы генерирует приватный ключ, хранит его у себя в надёжном хранилище и никому не показывает. Его публичная пара используется для аутентификации на каждом узле.  За каждым приватным ключом алгоритмически закреплён 1 ленд, на который у владельца ключа есть полные права. Авторизованно писать в этот ленд может только он. Все сенсоры пишут свои показания в свои ленды, что исключает возможность подделки показаний другими узлами.  Каждый контроллер, допускающий управление, создаёт ещё один ленд (intent), права на управление которым есть только у администратора. Даже сам контроллер не может в него писать. А вот админ может выдавать права на запись в этот ленд операторам.  У оператора, которому разрешено менять intent, автоматически появляется интерфейс для управления контроллером. Контроллер слушает intent и реагирует на его изменения.  У вендора есть свой приватный ключ и соответствующий ему ленд. В этот ленд он пишет код ПО и информацию о сроках лицензии. После чего выгружает этот ленд в виде пакета, который передаётся клиенту, чтобы инженер поддержки загрузил пакет в систему, что приведёт к обновлению ленда вендора в системе заказчика.  Все узлы системы слушают ленд вендора, и обнаружив свежий код для своего типа контроллера и проверив сроки лицензии для своего публичного ключа, устанавливают обновление.  $hyoo_crowd - библиотека для реактивной работы с БД в памяти.  $hyoo_sync - библиотека для синхронизации БД с ФС и с другими узлами.    Каждый юнит содержит:  Land - область атомарной синхронизации  Auth - автор юнита  Head+Self - идентификатор юнита  Prev+Next - частичный порядок среди соседних юнитов  Time+Aeon - время внесения данных в систему  Size+Data - сырые данные  Sign - авторская цифровая подпись  Устаревшие юниты отсеиваются, а оставшиеся упорядочиваются одинаково на всех узлах в соответствии с CvRDT подходом.    При установлении соединения, партнёры обмениваются векторными часами, говорящими о том, какие юниты у них есть есть.  Получив показания часов партнёра, каждый узел начинает слать ему те юниты, которых у того нет.  Каждый узел шлёт сердцебиения для поддержания соединения.  Долгое отсутствие сообщений от партнёра приводит к обрыву связи.  Обрыв связи - штатная ситуация, не влияющая на корректность синхронизации.  Каждый узел может синхронизироваться со множеством других узлов одновременно не впадая в состояние гонки.  Исходные коды  Установлен docker и docker-compose.  Установлена NodeJS 18.  С него открываются пользовательские интерфейсы.  Тут и далее тесты запускаются автоматически в процессе сборки:  Для каждого экземпляра необходим свой private_key, его можно сгенерировать в админке, на странице "Private key".  Каждый запущенный экземпляр создаёт новый контроллер, идентификатор которого выводит в консоль при запуске:  Этот идентификатор надо добавить в админке, чтобы на дашборде появился интерфес работы с этим контроллером.  Сборка и прогон всех тестов происходят автоматически в момент загрузки приложений, так как они у нас раздаются с девелоперского сервера. Результаты тестов выводятся в браузерной консоли.    Для удобства демонстрации в каждом новом окне создаётся новый пользователь. В заголовке у пользователя выводится идентификатор, его надо добавить в админке.  Приватный ключ администратора зашит в коде для удобства демонстрации.  Приватный ключ вендора зашит в коде для удобства демонстрации.  Для каждой роли у нас есть отдельные веб приложения для работы с системой:   Роль   Имя приложения   Описание приложния   👨 Наблюдатель     👨 Оператор   $tec_operator_dash   Дашборд с показаниями датчиков и, если есть права, элементами управления.   🧔 Инженер   $tec_operator_upload   Сервисная консоль, через которую инженер загружает пакеты с обновлениями лицензий и ПО.   🤴 Админ   $tec_domain_admin   Консоль администратора, через которую он настраивает пользователей, их права и регистрирует узлы.   🎅 Вендор   $tec_vendor_manager   Консоль вендора, через которую он готовит пакеты с обновлениями лицензий и ПО.  Приватный ключ оператора генерируется на его машине. На основе публичного ключа формируется его идентификатор, который выводится в шапке дашборда оператора. Администратор вносит этот идентификатор в систему и даёт ему понятное имя.    Приватный ключ контроллер генерирует и сохраняет у себя. На основе публичного ключа формируется его идентификатор, который выводится в консоли. Администратор вносит этот идентификатор в систему и даёт ему понятное имя.    Администратор указывает какой пользователь имеет право управлять каким контроллером:    Права можно только выдавать, но нельзя забирать. У контроллера может быть реализована специальная задача для сброса прав к дефолтному состоянию, когда права есть только у администратора.  Важно отметить, что права на управление не дают возможность подделывать показания.  Оператор видит показания всех сенсоров, но управлять может только теми, которыми ему разрешил администратор, через политики безопасности.    Важно отметить, что проверка прав осуществляется идентично, что на самом контроллере, что на сервере синхронизации, что в пользовательском интерфейсе. Это значит, что если видны доступны управления, то оператор действительно может управлять. А если не видны, то точно не может, и пытаться обходить проверку бесполезно.      Доступна любому пользователю. Позволяет загружать пакеты с любыми авторизованными обновлениями: от лицензий, до ПО. Фактически, пакет - это часть БД, переносимая не через прямую синхронизацию, а через любые, даже не защищённые, каналы связи.    Все тесты лежит в проекте в файлах с расширением test.ts и являются компонентными.  Помимо функциональных, тесты аутентификации и авторизации CROWD запускаются автоматически при сборке проекта.  Запускаются автоматически при сборке соответствующих сервисов.    Легенда: ✅позитивный, ❌негативный  Тесты сценариев работы оператора:  ✅ Аутентичное отображение показаний сенсора.  ✅ Авторизованное управление состоянием драйвера.  ❌ Попытка неавторизованного управления состоянием драйвера.  Легенда: ✅позитивный, ❌негативный  ❌ Попытка установки обновления на контроллер без лицензии.  Поднять инфраструктуру в докере.  Внести изменения в код /tec/power/service/start/start.node.ts добавив вывод в консоль cлова TEST при запуске.  Собрать сервис по инструкции.  Открыть консоль вендора на вкладке упаковки кода.  Установить тип пакета в "Power Driver".  Загрузить собранные файлы модифицированного сервиса.  Выгрузить пакет с обновлением ПО.  Открыть сервисную консоль.  Загрузить пакет с обновлением ПО.  Убедиться, что контроллер сообщил об истечении срока лицензии и не перезапустился.  ❌ Попытка установки обновления на контроллер с не валидной лицензией.  Поднять инфраструктуру в докере.  Открыть консоль вендора на вкладке управления лицензиями.  Установить время истечения лицензии на вчера.  Выгрузить пакет с лицензией.  Внести изменения в код /tec/power/service/start/start.node.ts добавив вывод в консоль cлова TEST при запуске.  Собрать сервис по инструкции.  Открыть консоль вендора на вкладке упаковки кода.  Установить тип пакета в "Power Driver".  Загрузить собранные файлы модифицированного сервиса.  Выгрузить пакет с обновлением ПО.  Открыть сервисную консоль.  + Загрузить пакет с лицензией.  Загрузить пакет с обновлением ПО.  Убедиться, что контроллер сообщил об истечении срока лицензии и не перезапустился.  ✅ Установка авторизованного обновления на контроллер с валидной лицензией.  Поднять инфраструктуру в докере.  Открыть консоль вендора на вкладке управления лицензиями.  Установить время истечения лицензии на завтра.  Выгрузить пакет с лицензией.  Внести изменения в код /tec/power/service/start/start.node.ts добавив вывод в консоль cлова TEST при запуске.  Собрать сервис по инструкции.  Открыть консоль вендора на вкладке упаковки кода.  + Установить тип пакета в "Power Driver".  Загрузить собранные файлы модифицированного сервиса.  Выгрузить пакет с обновлением ПО.  Открыть сервисную консоль.  Загрузить пакет с лицензией.  Загрузить пакет с обновлением ПО.  Убедиться, что контроллер сообщил об успешном обновлении, перезагрузился и вывел сообщение TEST.  ✅ Установка продления лицензии с авто установкой ожидавших обновлений.  Поднять инфраструктуру в докере.  Открыть консоль вендора на вкладке управления лицензиями.  Установить время истечения лицензии на завтра.  Выгрузить пакет с лицензией.  Внести изменения в код /tec/power/service/start/start.node.ts добавив вывод в консоль cлова TEST при запуске.  Собрать сервис по инструкции.  Открыть консоль вендора на вкладке упаковки кода.  Установить тип пакета в "Power Driver".  Загрузить собранные файлы модифицированного сервиса.  Выгрузить пакет с обновлением ПО.  Открыть сервисную консоль.  Загрузить пакет с обновлением ПО.  Убедиться, что контроллер сообщил об истечении срока лицензии и не перезапустился.  Загрузить пакет с лицензией.  Убедиться, что контроллер сообщил об успешном обновлении, перезагрузился и вывел сообщение TEST.  ❌ Попытка установки неавторизованной лицензии.  Поднять инфраструктуру в докере.  Поменять зашитый в коде консоли вендора ключ на свеже сенерированный.  Убедиться, что консоль вендора автоматически перезапустилась.  Открыть консоль вендора на вкладке управления лицензиями.  Установить время истечения лицензии на завтра.  Выгрузить пакет с лицензией.  Открыть сервисную консоль.  Убедиться в появлении ошибки при попытке загрузить пакет с лицензией.  ❌ Попытка установки неавторизованного обновления.  Поднять инфраструктуру в докере.  Открыть консоль вендора на вкладке управления лицензиями.  Установить время истечения лицензии на завтра.  Выгрузить пакет с лицензией.  Поменять зашитый в коде консоли вендора ключ на свеже сенерированный.  Убедиться, что консоль вендора автоматически перезапустилась.  Внести изменения в код /tec/power/service/start/start.node.ts добавив вывод в консоль cлова TEST при запуске.  Собрать сервис по инструкции.  Открыть консоль вендора на вкладке упаковки кода.  Установить тип пакета в "Power Driver".  Загрузить собранные файлы модифицированного сервиса.  Выгрузить пакет с обновлением ПО.  Открыть сервисную консоль.  Загрузить пакет с лицензией.  Убедиться в появлении ошибки при попытке загрузить пакет с обновлением ПО.  Убедится, что сервис никак не отреагировал на попытку обновления.   Участник   Роль   Связь   Дмитрий Карловский   Проектировщик   https://t.me/nin_jin   Роман Коплёнов   Разработчик   https://t.me/koplenov   Павел Зубков   Разработчик   https://t.me/zubkov_p  Наше решение было проработано лучше, чем у остальных, не смотря на более амбициозные цели. Но из-за мелких багов с в докерфайле, у организаторов с ходу не завелось, а разбираться они не стали. Так что в финалисты мы не попали.  АЦП не доверенный у нас потому, что сигналы могут приходить с выбоенами, шумом или выходить за правдоподобные границы. Поэтому показания фильтруются прежде чем попасть в базу. В коде мы это не реализовали.  ЦАП недоверенный потому, что это внешняя для нас система. Но наш сигнал на неё подаётся целостный. Тут было не очень понятно в какой цвет красить. Я бы предложил ввести ещё один цвет для тех компонент, которые должны быть доверенными исходя из предположений безопасности, но находятся вне зоны нашей ответственности.  На картинке это плохо видно, но в красных квадратиках у нас существенно больше кода, чем в зелёных и жёлтых. А в помеченных фиолетовым кружком ещё на порядок больше.  Как таковой кибериммунитет у нас был не внутри одного узла, а уровнем выше. Тут для каждого сенсора и каждого устройства управления создаётся отдельный узел, который не доверяет никому. То есть драйвер датчика может сломать лишь свой узел, но не может напрямую управлять турбиной, так как управлять ею может лишь её узел эксклюзивно через прямую работу с драйвером устройства.  У нас нет блокчейна, но есть CRDT и асимметричная криптография.  Да, косяк на косяке. Всё куплено. Верните мои нервы!  Обсудить эту дичь можно в теме про распределённые системы на форуме Гипер Дев. Подписывайтесь там же на новости, чтобы не пропустить готовящиеся материалы про CROWDs, на котором уже работает десяток наших приложений. Но о них уже в другой раз.  Спасибо организаторам за уникальный опыт, участникам за реализацию всех задуманных фичей, и, конечно, читателям за интерес к нашему решению.   Актуальный оригинал на $hyoo_page.   Full Stack Overflow