docs(security): SEC-12 — цена не валидируется и в неcustodial-бэкенде
Проверено на smart-updown-server: GameService.submitBet не сверяет payload.entryPrice со своим priceSource, сравнение JSON-подсказки с tx лишь логирует log.warn и не отклоняет. Клиент подписывает entry_price сам. Зафиксирована инверсия: custodia-шлюз стенда эту дыру закрывает (цена из NATS на сервере), а неcustodial прод-бэкенд открыт. Переход на неcustodial без серверной сверки entry_price ухудшит положение.
This commit is contained in:
+1
-1
@@ -35,7 +35,7 @@
|
||||
|
||||
- [ ] **SEC-10. NATS без аутентификации** — `auth_required` не выставлен, анонимная публикация в шину проходит (проверено на тестовом subject; боевой не трогали). Пока цена условна — терпимо; как только станет денежной, у шины нет прав на запись и любой сможет напечатать свой курс. Фикс: auth + subject-ACL, шлюзу — read-only на `market.price.*`.
|
||||
- [ ] **SEC-11. Ключ релейера — единственная точка доверия в контракте** — контракт не проверяет соответствие цены рынку и принимает любое значение от подписанта (`create_bet.rs:75`, `close_bet.rs:62`). Модель «релейер = оракул» стандартна, но компрометация одного ключа `E7Hg…` = произвольный исход всех ставок. Фикс: on-chain оракул (Pyth/Switchboard) для боя.
|
||||
- [ ] **SEC-12. `entry_price` не проверяется контрактом** — передаётся в `create_bet` целиком на усмотрение вызывающего; контракт не может убедиться, что это цена момента `bet_time`. Место: `create_bet.rs:46,75`. Фикс: внешний верифицируемый фид.
|
||||
- [ ] **SEC-12. `entry_price` не проверяется ни контрактом, ни прод-бэкендом** — передаётся в `create_bet` целиком на усмотрение вызывающего; контракт не может убедиться, что это цена момента `bet_time` (`create_bet.rs:46,75`). **Проверено на прод-бэкенде `smart-updown-server`:** в `GameService.submitBet` цена из подписанной tx НЕ сверяется со своим `priceSource` — `payload.entryPrice` проходит насквозь; сравнение `entryPrice != payload.entryPrice` (`GameService.kt:100-118`) сверяет лишь JSON-подсказку с tx и на расхождении пишет `log.warn` («trusting the signed transaction»), не отклоняя. Валидируются только `paused`, парсинг tx, `payload.id == global.counter` и границы `amount`. **Клиент подписывает `entry_price` сам** → может зашить любое значение (`entry_price=1` → UP выигрывает почти всегда). **Важная инверсия моделей:** сегодня custodia-шлюз стенда эту дыру случайно ЗАКРЫВАЕТ (цена берётся из NATS на сервере, `gateway.ts:280`), а «правильный» неcustodial прод-бэкенд — ОТКРЫТ. Значит переход на неcustodial-модель (`/bet` принимает подписанную tx, как `smart-updown-server`) БЕЗ серверной проверки `entry_price` по своему оракулу сделает хуже, чем есть. Фикс: внешний верифицируемый фид (Pyth/Switchboard) + серверная сверка `entry_price` с допуском до ретрансляции.
|
||||
|
||||
## Отложено — зафиксировать как риск
|
||||
|
||||
|
||||
Reference in New Issue
Block a user