montana/Android/Внешний-аудит/07-Известные-ограничения.md
2026-05-18 22:11:45 +03:00

245 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 07. Findings tracker — известные ограничения
Открытый реестр всех известных уязвимостей, дефектов и архитектурных gap. Severity по шкале:
- **блокер mainnet** — запуск в production невозможен до закрытия
- **высокий** — производственный риск, обязательно закрыть до публичного релиза
- **средний** — допустимо запустить с явным acknowledgment
- **низкий** — косметика, document-hygiene
Все findings имеют **closure path** — конкретные шаги для устранения.
---
## Закрыто в v6.5.0 (Phase 1)
### CF-1 — Swallowed catch без логирования ✅
**Класс:** error surface (Pass 7).
**Severity:** средний.
**Closure:** `commit cf1` (v6.5.0). 10/13 catch теперь логируют `Log.w(TAG, ...)`. Остаётся 3 в `Thread.sleep` (interrupt handling, acceptable per Kotlin pattern).
### CF-2 — Regex JSON parser ✅
**Класс:** parser robustness (Pass 8/10).
**Severity:** средний.
**Closure:** `commit cf2` (v6.5.0). Заменён на `org.json.JSONObject` с `optDouble/optString/optBoolean` и fail-safe NaN-проверкой.
### CF-3 — BIP39 wordlist integrity check ✅
**Класс:** integrity / supply chain (Pass 0 [C-9]).
**Severity:** **блокер mainnet** до закрытия.
**Closure:** `commit cf3` (v6.5.0). Hardcoded SHA-256 `2f5eed53...dbda` в `MainActivity.bip39()`. Fail-closed: возвращает пустую строку → JS бросает «bip39 list size: 0» → создание кошелька невозможно.
### CF-5 — balances.json race condition ✅
**Класс:** concurrency (Pass 8).
**Severity:** средний.
**Closure:** `commit cf5` (v6.5.0). Atomic `with_state_lock()` через отдельный `.lock` файл с единым `LOCK_EX` на read+modify+write.
### CF-7 — silent JSON swallow на backend ✅
**Класс:** error surface (Pass 7).
**Severity:** низкий.
**Closure:** `commit cf7` (v6.5.0). `force=True` + явный `400 invalid json` с detail.
### F-1 — Stale `assigned_node` поле ✅
**Класс:** consistency drift (Pass 13).
**Severity:** низкий.
**Closure:** `commit f1` (v6.5.0). Удалены `assigned_node`/`assigned_ts` поля из всех записей balances.json.
### F-3 (частично) — anon-bloat в balances.json ✅
**Класс:** state lifecycle (Pass 18 / [I-14]).
**Severity:** средний.
**Partial closure:** `commit f3` (v6.5.0). `/api/vpn/admin/purge` endpoint удаляет inactive 30+ days с balance=0. Manual trigger.
**Остаётся open:** automated daily cron (см. ниже F-3.1).
---
## Открытые findings
### F-2 — Heartbeat без cryptographic authentication ⛔
**Класс:** authentication / Sybil (Pass 19, Pass 22).
**Severity:** **блокер mainnet**.
**Поверхность:** `POST /api/vpn/heartbeat` принимает `{"address": "<40-hex>"}` и проверяет только `request.remote_addr ∈ MONTANA_NODES`. Никакой подписи владельца адреса не требуется.
**Атака:**
1. Атакующий поднимает Montana VPN клиент (открытый VLESS link).
2. Генерирует 10⁶ случайных 40-hex адресов.
3. Шлёт 10⁶ heartbeat каждые 5 секунд через VPN.
4. Backend начисляет 0.001 × 5 × 10⁶ = 5000 Ɉ/период на fake-адреса.
**Defense сейчас:** нет.
**Closure path:**
1. **Phase 3 (M-VPN-3):** Falcon-512 keypair generation в Android — каждый кошелёк имеет `(pubkey, secretkey)` от seed.
2. Heartbeat body расширяется: `{address, window_index, exit_node, signature}` где signature — Falcon-512 над `(address || window_index || exit_node)`.
3. Backend хранит pubkey per address (заполняется при первом heartbeat) → проверяет signature над всеми последующими.
4. Atomic operation: верификация подписи → начисление credit.
**Cost estimate:** 2 недели (JNI bridge для `pqcrypto-falcon` + key derivation от BIP39 seed + backend signature verify).
---
### F-4 — balances.json НЕ реплицируется на узлы Montana ⛔
**Класс:** persistence / SPOF.
**Severity:** **блокер mainnet**.
**Поверхность:** balance state живёт **только** в `/var/lib/montana-vpn-balance/balances.json` на Moscow. Если Moscow упадёт безвозвратно (диск, hosting termination, государственный захват) — все начисленные Ɉ потеряны.
**Что я ошибочно заявлял раньше:** «всё сохраняется на узлах через `montana-orchestrator.service`». **Неверно** — orchestrator занимается регистрацией узлов, не балансами.
**Closure path:**
1. **Phase 2 (M-VPN-1):** реплицировать balances.json на Helsinki + Frankfurt + NewYork через `rsync` daily. Mitigation, не fix.
2. **Phase 3 (M-VPN-2):** интегрировать с TimeChain — heartbeat становится подписанной операцией `0x06 VpnHeartbeat` → попадает в proposal → cemented через консенсус → AccountTable обновляется на ВСЕХ узлах. Authoritative persistence.
**Cost estimate:** Phase 2 — 3 дня. Phase 3 — 2 недели (новый opcode в спеке + mt-account изменения + montana-node integration).
---
### F-6 — Seed в plain text без шифрования
**Класс:** privacy at rest (Pass 19).
**Severity:** высокий (на rooted устройствах).
**Поверхность:** `localStorage.setItem("m.seed", "ranch basket resource ...")` в WebView Local Storage leveldb.
**Атаки:**
- Root доступ к `/data/data/quest.montana.vpn/app_webview/Default/Local Storage/leveldb/` → читает плоский текст
- Forensic image устройства → offline analysis
- Backup через ADB → seed в backup
**Closure path:**
- User passcode + PBKDF2(passcode → AES key) → wrap seed AES-GCM
- Или Android Keystore (hardware-backed) для wrap
**Cost estimate:** 1 неделя (UX flow + crypto + миграция existing wallets).
---
### F-7 — Backup confirmation отсутствует
**Класс:** UX-as-security.
**Severity:** высокий (вероятная потеря денег пользователями).
**Поверхность:** см. `06-Восстановление.md` §6.
**Closure path:** новый экран `s-backup-verify` между `s-auth` и `s-main` при создании.
**Cost estimate:** 1 день.
---
### F-8 — BIP44 несовместимость для cross-wallet import
**Класс:** narrative-model divergence.
**Severity:** средний (UX).
**Поверхность:** см. `06-Восстановление.md` §5. 24 слова Montana → импорт в Trust/MetaMask показывает пустые балансы.
**Closure path** (выбор):
- A. Добавить UI warning при показе seed
- B. Apply for SLIP-44 coin type + переход на BIP44 derivation path → cross-wallet import работает
Option A — 30 минут. Option B — недели (SLIP-44 registration + backward-incompatible breaking change существующих addresses).
---
### CF-4 — Reality keys + UUID в 19 местах ([C-1] SSOT violation)
**Класс:** SSOT.
**Severity:** средний.
**Поверхность:** см. `04-Сетевой-слой.md` §15.
**Closure path:** Phase 2 — Rust crate `mt-vpn-config-gen` читает keys из `mt-genesis::ProtocolParams::reality_keys`, генерирует все 19 конфигов.
**Cost estimate:** 3 дня.
---
### CF-6 — `https://montana.local/` synthetic baseURL
**Класс:** production naming [C-12].
**Severity:** низкий.
**Closure:** переименовать в `https://montana.quest/app/` (синтетический, naружу не идёт). 5 минут.
---
### F-3.1 — Automated purge cron отсутствует
**Класс:** state lifecycle (Pass 18).
**Severity:** низкий.
**Closure:** добавить systemd timer `montana-vpn-balance-purge.timer` daily + автоматический вызов в самом heartbeat (раз в 1000 операций). 1 час.
---
### CF-recovery-tests — Recovery E2E test отсутствует
**Класс:** Pass 20 user recovery trace.
**Severity:** высокий.
**Поверхность:** см. `06-Восстановление.md` §4. Нет automated test что mnemonic → adr воспроизводимо между устройствами.
**Closure path:**
- Add `BIP39DerivationTest.kt` unit test (JVM) — берёт известный mnemonic, проверяет адрес против hardcoded expected hex
- Add `RecoveryE2ETest.kt` instrumented test — то же, но в реальном WebView
**Cost estimate:** 2 дня.
---
### F-reality-pq — Reality X25519 не пост-квантово
**Класс:** [I-1] PQ-secure compliance.
**Severity:** низкий (на горизонте 10 лет).
**Поверхность:** Reality использует X25519 для key exchange — уязвим к квантовому компьютеру (Shor).
**Closure path:** upstream XTLS реализация PQ-Reality (work in progress, не наша работа). На горизонте 5-10 лет (CRQC threat model).
---
### F-keystore-backup — Genesis keystore без backup procedure
**Класс:** operational security.
**Severity:** высокий.
**Поверхность:** `/Users/kh./Python/Ничто/Montana/Android/keystore/montana.keystore` хранится только на устройстве автора. Компрометация = malicious APK подписи.
**Closure path:** HSM или Shamir-split keystore на N доверенных лиц с threshold.
---
## Roadmap закрытия
### Phase 2 (M-VPN-1, ~1-2 недели) — Rust backend
- Заменить Flask `app.py` на Rust `mt-vpn-balance` (axum + sqlx + SQLite WAL)
- F-4 mitigation: rsync replication на 3 узла Montana
- CF-4 closure: `mt-vpn-config-gen` бинарь читает Reality keys из единого источника
- F-3.1: cron purge
- CF-recovery-tests: unit + instrumented tests
- F-7: backup verify screen
- F-8: UI warning
### Phase 3 (M-VPN-2/3, ~3-4 недели) — TimeChain integration
- F-2 + F-4 final closure: новый opcode `0x06 VpnHeartbeat` в `Montana Protocol v35.26`
- mt-account реализация apply_vpn_heartbeat (50+ тестов)
- montana-node accepts heartbeat в mempool → cemented через consensus
- AccountRecord.balance обновляется через canonical apply pipeline
- Android JNI bridge для Falcon-512
- F-6 closure: encrypted seed через user passcode
### Phase 4 (опциональная, поздно) — Hardening
- F-reality-pq: переход на PQ-Reality когда XTLS upstream готов
- F-keystore-backup: HSM или Shamir split