Что может сделать злоумышленник, зная исходники прошивки, но не имея доступа к секретам устройства.
Прошивка публична → известен формат пакетов, длины, алгоритмы (X25519, HMAC-SHA256, HKDF). Эфир BLE открыт → можно слушать advertise и GATT-writes. Никаких секретов в прошивке и в эфире не лежит.
Все ключи хранятся:
owner_secret (32 байта) — только в ESP NVS и на телефоне хозяина. Выводится через ECDH X25519 в момент pair, по эфиру никогда не передаётся в открытом виде.guest_key — на телефоне гостя. Приходит с сервера в bundle через защищённый WSS-канал, по BLE никогда.| Атака | Защита |
|---|---|
| Подделать FIRE | HMAC-SHA256. Без owner_secret или guest_key — 2128 перебор, неосуществимо. |
| Подделать TIME write | Тот же HMAC поверх bleId + epochMs. |
| Replay sniffed advertise | Counter монотонный, при повторе/понижении HMAC не сходится. |
| Replay sniffed fire | Nonce-ring инвалидирует использованные nonce. |
| Откатить часы ESP назад | Ratchet — любой TIME < ratchet отвергается. Ratchet в NVS, переживает power-off. |
| Использовать просроченный bundle | После работы ESP ratchet ≥ последнее настоящее время. validUntil просроченного бандла < ratchet → fire fails по TTL. |
| Сделать +1 год и обнулить всех | Cap +24ч на одну гостевую TIME-запись. Хозяин unlimited (он доверенный). |
| Pair'нуться вторым «хозяином» поверх | После pair ESP сохраняет owner_secret в NVS и больше в pair-mode не входит без factory-reset. |
Условие: есть валидный (не просроченный) guest-bundle.
Действие: каждый раз когда в зоне — пишет TIME с прыжком +24ч.
Лимит: +24ч за сессию, и нужен fresh fire (если sync был <1ч назад). После 10 заходов ratchet ушёл на 10 дней вперёд → у других легитимных гостей токены кажутся протухшими.
Самовредительство: его собственный токен тоже считается с фейкового времени → быстрее «протухнет» по нему же.
Лечение: хозяин приходит, пишет реальное время — ratchet не двинется (нельзя назад), но новые гостевые токены выпускаются с актуальным validUntil → они валидны для дальнейших гостей. Восстановление требует только обновления валидности на сервере.
Серьёзность: временный DoS до прихода хозяина. Не катастрофа.
Условие: физически в радиусе ESP в 90-секундном окне после нажатия кнопки pair хозяином.
Действие: подменить свой X25519 public key в pair-handshake.
Результат: ESP спарится с атакующим, не с хозяином. Хозяин думает что спарился, но его телефон не сможет ничего открыть.
Защита сейчас: только окно времени + физическое присутствие хозяина (он сам видит, что pair-индикатор отвалился, и повторяет процедуру).
Усиление: добавить простой verification code (4 цифры на дисплее ESP / в Serial), который хозяин подтверждает в приложении. Сейчас этого нет.
Серьёзность: окно атаки узкое, требует одновременно быть рядом и в нужные 90 секунд. На практике мало реализуемо.
Условие: физический доступ к ESP, удержание кнопки long-press.
Действие: NVS стирается, owner_secret удаляется, ESP уходит в pair-mode.
Результат: атакующий может перепарить ESP под себя. Хозяин лишается доступа.
Защита: физическая установка ESP в защищённое место (внутри коробки, под крышкой).
Серьёзность: аналог «оторвать домофон с двери». Не криптографическая проблема.
Условие: физический доступ + flash dump (или secure boot/flash encryption отключены — а они сейчас отключены).
Действие: прочитать NVS с owner_secret.
Результат: полная компрометация устройства, всех гостевых токенов.
Защита: включить ESP32 secure boot + flash encryption (efuse, необратимо). Сейчас НЕ сделано.
Серьёзность: для бытового применения приемлемо. Для серьёзных объектов — надо secure boot.
Условие: в BLE-радиусе.
Действие: подключаться и не отключаться. NimBLE имеет ограниченное число одновременных соединений.
Результат: легитимные клиенты не могут подключиться пока атакующий держит слот.
Защита сейчас: только таймауты NimBLE.
Усиление: добавить idle-таймаут (если клиент не сделал валидный fire за 5 секунд — disconnect).
Серьёзность: временный DoS пока атакующий в эфире.
Действие: засыпать ESP мусорными writes.
Результат: ESP их режет, пишет в Serial. Никаких state-изменений. После ухода атакующего — норма.
Стандартное усиление для production:
Это не критично для текущего use-case, но если будут серьёзные объекты — добавлю.