Решил и я в рамках конкурса рассказать о своём вкладе в развитие open source. Речь про open source блокчейн Hyperledger Fabric. Блокчейн активно используется в разных сферах: цифровые валюты центробанков (Беларусии, Нигерии), операторами информационных систем цифровых финансовых активов, электронное голосование, энергетика, здравоохранение и др.
В этой статье я расскажу:
как я обнаружил проблему;
как я создал свой первый open source: смарт-контракт для решения найденной проблемы;
как повлиял на создание патча для open source блокчейна Hyperledger Fabric, устраняющего проблему.
Исследуя смарт-контракт коммерческого проекта на потенциальные проблемы безопасности в рамках своей задачи на одном из прежних мест работ, я обратил внимание на потенциально небезопасное описание функций GetTxTimestamp() и GetHistoryForKey(). В зависимости от логики смарт-контракта, в случае использования этих функций без проверок значений, могли быть потенциальные проблемы, связанные с манипуляцией временем транзакции со стороны клиента. Я смог найти лишь один готовый вариант решения озвученной проблемы (4-х летней давности) - TimeFabric (статья, исходники). Согласно описанию, вариант является патчингом исходного кода Hyperledger Fabric. Заявлено, что подходит для версии 1.4 и 2.0. Т.е. перед применением развёрнутый блокчейн нужно пропатчить. И в дальнейшем, может появиться необходимость патчинга блокчейна при его обновлении. Судя по всему, проект более не поддерживается. Что вызывает вопрос относительно возможности использования на версиях блокчейна, вышедших за последние 4 года.
Подробное описание проблемы манипуляции временем, макет и результаты эксперимента я описывал в статье Манипуляция временем транзакции в блокчейне Hyperledger Fabric. Т.к. первоначально эта проблема была выявлена мной в рамках выполняемой мной работы у работодателя - я сообщил о находке своему непосредственному руководителю (отдел занимался безопасностью блокчейнов). Я надеялся, что дальнейшие шаги по находке будем делать совместно с коллегами по отделу. Руководитель, на тот момент, был без практического опыта в безопасности: не только блокчейна, а вообще в сфере ИБ. Был у него опыт разработки в блокчейнах. Более полугода руководитель никак не реагировал на мою находку. К тому времени созрели условия для моего ухода из организации (что я и сделал). Спустя время, я решил довести начатое мной до конца самостоятельно. Этот путь занял у меня почти всё лето 2024 года. В итоге моим первым шагом в open source стал PoC код смарт-контракта на Go, показывающий суть проблемы. У меня не было опыта создания смарт-контрактов для Hyperledger Fabric. Поэтому, я сначала помучал пару ChatGPT-подобных сервисов (уже и не помню каких). Коды, которые они выдавали, были нерабочими. Так что, пришлось самостоятельно разбираться как "доработать напильником" (отсылка к анектодам). Ещё месяц заняла реализация защиты. Это был мой второй шаг в open source. И здесь уже пришлось попотеть: хотелось сделать проект понятный для использования другими. Цель: сделать смарт-контракт (оракул времени), который будет источником верного времени для других смарт-контрактов (решил использовать NTP и NTS сервера в качестве источника точного времени). Это позволит использовать оракул времени смарт-контрактами, написанными на любых поддерживаемых блокченом языках. Для этого нужно было: написать понятный код, снабдить его комментариями и сделать юнит-тесты (добившись хорошего покрытия кода). А также, написать подробную документацию по целям и вариантам использования проекта. Примерно так я себе представлял более или менее приличный open source проект (исходя из своего опыта использования стороннего open source). И хотелось как-то соответствовать этой планке. Я не профи программист, код писать не люблю. Пришлось себя перебороть ради достижения этой цели. Были у меня и свои внутренние требования по безопасности и отказоустойчивости: должна поддерживаться возможность обращения к разным серверам времени - на случай, если какой-либо сервер точного времени выйдет из строя. Кроме того, нужно было проверить устойчивость разрабатываемого решения к атаками типа "человек посередине" (т.к. при использовании NTP-сервера это актуальная проблема). В итоге, я остановился на open source решении для работы с NTS серверами для Go. И как ещё один вариант - сделал возможность взаимодействия с NTP-серверами (используя библиотеку для NTP того же автора, что и библиотека для NTS). Также нужно было решить проблему централизации (т.к. речь идёт о распределённой системе). Решением стало использование нескольких оракулов времени, каждый из которых сконфигурирован на обращении к своему уникальному серверу времени.
Набив немного руку на создании PoC кода, при создании оракула времени, я уже обходился без ChatGPT. Но, я заново прошёл некоторые уроки из бесплатного курса "Основы Go" Яндекс.Практикума: ранее не приходилось делать юнит-тесты и оценивать покрытие ими кода (т.к. до этого лишь писал несложные коротенькие программы для самого себя и коллег, там хватало и краткого readme). В итоге удалось добиться покрытия кода в 84,4%. Кроме того, я использовал golangci-lint - для улучшения качества кода и проверок возможных проблем безопасности.
Также, в процессе разработки, много времени заняла проблема недоступности NTS серверов через сеть моего домашнего провайдера: я ранее не делал программы для работы с NTS. Поэтому не сразу понял, что проблема на стороне провайдера, а не в моём коде. На разбор проблемы я убил пару дней. Лишь позже додумался всё проверить через интернет моего мобильного оператора (и с ним проблема ушла).
После всего этого я презентовал своё решение в сообществе любителей Hyperledger Fabric. В сообществе присутствовали в т.ч. и разработчики этого блокчейна. Они начали меня уверять, что проблемы никакой нет и я якобы "борюсь с ветреными мельницами". В целом, проблема была известна, как минимум, с 2019 года. Поэтому, я засомневался и решил перепроверить: вдруг я всё же ошибся?! Но, повторная проверка убедила меня в моей правоте. Позже, проблему всё же признали (и даже поблагодарили). Патч доступен с версии 3.0.0. Из описания релиза версии 3.0.0:
"TimeWindowCheck for proposal timestamps
New
TimeWindowCheck
endorsement authFilter configured atpeer.handlers.authFilters.name
checks the timestamp of a proposal request against endorsing peer time,
using the time window configured atpeer.authentication.timewindow
.
This check helps to ensure that the proposal timestamp that eventually gets committed in a transaction is accurate relative to the endorsing peers."
В ветке 2.5.х проблему устранять не стали (не знаю почему). При этом, ветка обновляется. Так что, пользователи ветки 2.5 могут взять за основу мою разработку.
Уязвимости также присвоен идентификатор CVE-2024-45244.