security: round 3 hardening (CSRF double-submit, TRX MITM, container hardening)

This commit is contained in:
ZOMBIIIIIII
2026-05-12 01:47:58 +03:00
parent c8bc40af97
commit 8dc0855827
37 changed files with 1852 additions and 318 deletions

67
README.md Normal file
View File

@@ -0,0 +1,67 @@
# CryptoWallet API — Deployment Bundle (v5.0 custodial)
Multi-chain **custodial** wallet API (ETH / BSC / BTC / TRX / SOL).
- Сервер генерит mnemonic, хранит зашифрованной (AES-256-GCM, master-key из HashiCorp Vault)
- Сервер сам подписывает tx по запросу юзера (юзер на клиенте жмёт "подтвердить")
Auth — JWT (BITOK), секреты — HashiCorp Vault (AppRole).
## Pre-deploy setup (один раз навсегда)
```bash
# 1. Master-key в Vault
vault kv put dev-secrets/crypto/master key=$(openssl rand -hex 32)
# 2. DB schema
psql -h 72.56.9.76 -U postgres_user -d postgres -f cryptowallet-schema.sql
```
⚠️ **Master-key менять нельзя** — все existing encrypted_mnemonic станут нерасшифровываемыми. Сервис логирует WARN если в Vault ключ изменился.
## Deploy
```bash
scp -P 2222 -r deployserver/ server@176.124.213.102:~/cryptowallet/
ssh server@176.124.213.102 -p 2222
cd ~/cryptowallet && cp .env.example .env && nano .env && ./start.sh
```
В `.env` обязательны: `VAULT_ADDR`, `VAULT_ROLE_ID`, `VAULT_SECRET_ID`, `JWT_ISSUER`, `JWT_AUDIENCE`, `CORS_ORIGINS`.
## Endpoints (24)
| Method | Path | Описание |
|---|---|---|
| GET | /api/health | Liveness (public) |
| GET | /api/docs | Swagger UI |
| POST | **/api/wallets/create** | **Сервер создаёт коша** (no body, returns addresses) |
| GET | /api/wallets | Список адресов юзера |
| POST | **/api/wallets/mnemonic/reveal** | Reveal seed (body confirm + 5/час) |
| GET | /api/wallets/{chain}/balance | Баланс |
| GET | /api/wallets/{chain}/transactions | История tx |
| POST | **/api/wallets/{chain}/send** | **Сервер подписывает + broadcast** |
| ... | /api/btc/* /api/tron/* /api/sol/* /api/bsc/* /api/relay/* | Proxy endpoints |
## Security highlights
- **AES-256-GCM** для encrypted_mnemonic (12-byte random IV, 16-byte auth tag, fail-secure)
- **Master-key set-once** (rotation запрещена)
- **Race-safe createWallet**: `db.transaction` + `UPDATE WHERE encrypted_mnemonic IS NULL`
- **TRX MITM defense**: local recompute txID + verify raw_data перед подписью
- **EVM gas cap** 500 gwei (применён к tx, не только check)
- **Address checksum validation** (BTC bitcoinjs-lib, TRX bs58check, SOL PublicKey, EVM EIP-55)
- **assertAddressMatch** — derived(mnemonic, path) === DB.address перед подписью
- **SOL confirmTransaction** — ждём подтверждения
- **BTC** P2WPKH bech32, fee fallback 15 sat/vB + 1.1x safety, dust 294, broadcast 20s timeout
- **POST mnemonic/reveal** + CSRF + body confirm token + 5/час + audit-log
- **Logger sanitization**: password/token/mnemonic/hex64/BIP39-phrase patterns
- **Audit log** `logs/audit.log` (wallet.create / wallet.send / mnemonic.reveal)
- **Hourly key rotation**: JWT keys + CSRF secret из Vault (master-key НЕ ротируется)
- **Fail-fast**: сервис не стартует без master-key, JWT_ISSUER, JWT_AUDIENCE
## Update / Rebuild
```bash
scp -P 2222 -r deployserver/apps server@176.124.213.102:~/cryptowallet/
ssh server@176.124.213.102 -p 2222 'cd cryptowallet && docker compose up -d --build'
```