Files
bal-server/docs/08_security_audit.md
svatantrya eacb2e1450 docs: update knowledge base to match current codebase
- Fix framework references (actix-web, not hyper)
- Update all env var names (BAL_SERVER_*/BAL_PUSHER_* prefix)
- Add validation.rs module documentation
- Fix function signatures in xpub.rs and db.rs
- Update API response formats (InfoResponse, StatsResponse)
- Fix database schema (date_creation/date_update, push_err, tbl_stats)
- Mark fixed vulnerabilities with current status
- Add Docker support and actix tuning documentation
- Remove outdated references (confy, bal-stats.rs.dontcompile)
- Add regression test summary table
2026-07-20 15:43:20 -04:00

157 lines
9.4 KiB
Markdown

# Security Audit
## Quick Reference
- **What this file contains:** threat model, vulnerability assessment, hardening recommendations, and a security checklist.
- **See also:** [AGENTS.md](AGENTS.md), [07_deployment_and_ops.md](07_deployment_and_ops.md), [06_database_schema.md](06_database_schema.md), [03_architecture_and_data_flow.md](03_architecture_and_data_flow.md), [04_modules_detail.md](04_modules_detail.md)
---
## Threat Model
### Assets
1. **`bal.db` (SQLite database):** Contains all transaction details, user IP addresses, and stats data. Single unencrypted file on disk. WAL mode enabled for concurrent access safety.
2. **Private Keys (`privkey.pem`):** Used to sign statistics payloads for the `welist` server. Located in `.gitignore`.
3. **Bitcoin Node (`bitcoind`) Access:** The `bal-pusher` has RPC access. Compromise allows arbitrary transaction broadcasting.
4. **Server Availability (`bal-server`):** Public-facing HTTP endpoint. DoS attacks threaten service availability.
### Attackers
- **Remote Anonymous Users:** Can interact with the API via public HTTP. No credentials required.
- **Network Man-in-the-Middle (MITM):** TLS termination is via Nginx reverse proxy. The `bal-server` itself is plain HTTP.
- **Local/Insider Threats:** If the server is compromised, the attacker can access `bal.db`, private keys, and env files.
---
## Vulnerability Assessment
### 1. SQL Injection (FIXED)
**Severity:** HIGH | **Status:** Fixed
**Location:** `src/db.rs`, `src/bin/bal-server.rs`, `src/bin/bal-pusher.rs`
**Description:** SQL queries previously used `format!()` for string interpolation. All queries now use parameterized statements (`?` with `bind()`).
**Mitigation Applied:** All SQL queries rewritten with prepared statements. `execute_insert` uses parameterized batch inserts. `check_duplicate_txids` uses parameterized `IN` clauses. `echo_stats` handler uses prepared statements for chain filtering.
**Regression Tests:** `tests/sql_injection_tests.rs` (3 tests).
### 2. Panic on Untrusted Input (FIXED)
**Severity:** HIGH | **Status:** Fixed
**Location:** `src/bin/bal-server.rs`, `src/bin/bal-pusher.rs`
**Description:** All `unwrap()`/`expect()` calls on critical paths have been replaced with safe error handling.
**Mitigation Applied:**
- `bal-server`: `from_utf8` returns 400, `sqlite::open` uses `open_db()` with validation, all handlers return proper HTTP status codes.
- `bal-pusher`: RPC failures log errors + sleep + retry (no panic), ZMQ `recv` uses `set_rcvtimeo(5000)`, `fs::read_to_string` uses `match` + 500, `cfg.lock()` uses `poisoned.into_inner()` recovery.
**Regression Tests:** `tests/panic_regression_tests.rs` (2 tests).
### 3. Secret Leakage (FIXED)
**Severity:** HIGH | **Status:** Fixed
**Location:** `make_release.sh`, `.gitignore`
**Description:** `make_release.sh` now loads `TOKEN` from `.env` (`.env.example` provided). Private keys (`.pem`, `.key`) are in `.gitignore`. `generate_keys.sh` sets `chmod 600` on generated keys.
**Mitigation Applied:** Secrets removed from scripts and repository. `.gitignore` protects `.env`, `*.pem`, `*.key` files.
**Regression Tests:** `tests/secret_leakage_tests.rs` (3 tests).
### 4. Denial of Service (DoS) (FIXED)
**Severity:** HIGH | **Status:** Fixed
**Location:** `src/bin/bal-server.rs` (HTTP), `src/bin/bal-pusher.rs` (ZMQ)
**Description:** All DoS vectors mitigated via actix-web migration.
**Mitigation Applied:**
- Body size limit: `PayloadConfig::default().limit(max_body_size)` via `BAL_SERVER_ACTIX_MAX_BODY_SIZE` (default 1 MiB).
- Rate limiting: `actix-governor` with token-bucket per endpoint (`BAL_SERVER_ACTIX_PUSHTXS_PER_SEC`/`BURST`).
- Connection limits: `workers(4)` and `max_connections(100)` via `BAL_SERVER_ACTIX_WORKERS`/`MAX_CONNECTIONS`.
- Body timeout: configurable via `BAL_SERVER_ACTIX_TIMEOUT_SECS`.
- ZMQ timeout: `set_rcvtimeo(5000)` prevents infinite blocking.
- RPC retry: sleep + retry on connection failure instead of panic.
### 5. SSRF / Network Abuse via `reqwest` (FIXED)
**Severity:** MEDIUM | **Status:** Fixed
**Location:** `src/bin/bal-pusher.rs`, `src/validation.rs`
**Description:** URL validation prevents redirecting requests to internal/private IPs.
**Mitigation Applied:** `is_valid_welist_url()` in `src/validation.rs` blocks localhost, loopback, RFC1918, link-local, multicast, unspecified, and IPv6 unique-local addresses. HTTPS-only scheme enforced.
**Regression Tests:** `tests/ssrf_tests.rs` (integration) + 8 unit tests in `src/validation.rs`.
### 6. Insecure Database Access (FIXED)
**Severity:** MEDIUM | **Status:** Fixed
**Location:** `src/db.rs`, `src/bin/bal-server.rs`, `src/bin/bal-pusher.rs`
**Description:** Database path validation and WAL mode for concurrent access.
**Mitigation Applied:**
- `open_db()` rejects `..` traversal, forbidden system directories (`/etc`, `/proc`, `/sys`, `/dev`, `/usr`, `/bin`, `/sbin`, `/lib`, `/opt`), symlinks, and non-regular files.
- WAL mode (`PRAGMA journal_mode=WAL`) with retry logic (up to 5 attempts).
- `busy_timeout=5000` for concurrent access.
- `bal-server` uses `Arc<Mutex<Connection>>` for thread-safe shared access.
**Regression Tests:** `tests/db_path_validation.rs` (5 tests).
### 7. ZMQ Authentication and Encryption (OPEN)
**Severity:** MEDIUM | **Status:** Open
**Location:** `src/bin/bal-pusher.rs`
**Description:** ZMQ connection is plaintext TCP. No authentication (ZAP), no encryption (ZMQ_CURVE). If the ZMQ port is exposed, any attacker can subscribe to topics.
**Mitigation (Operational):**
- Bind ZMQ to `127.0.0.1` only.
- Firewall blocks external access to ZMQ ports.
- If public ZMQ is required, use ZMQ_CURVE with public-key cryptography.
### 8. Missing HTTPS / Insecure Server Communication (FIXED)
**Severity:** HIGH | **Status:** Fixed (Infrastructure)
**Location:** Nginx configuration, `contrib/nginx/bal-server.conf`
**Description:** TLS termination via Nginx reverse proxy. The `bal-server` intentionally does not implement TLS.
**Mitigation Applied:**
- Dedicated Nginx template with `listen 443 ssl http2`, Let's Encrypt paths.
- Security headers: `X-Frame-Options`, `X-Content-Type-Options`, `Referrer-Policy`.
- `client_max_body_size` matching `BAL_SERVER_ACTIX_MAX_BODY_SIZE`.
- HTTP 80 redirect to HTTPS.
- Deployment checklist ensures no accidental plain HTTP exposure.
### 9. Missing Input Validation (FIXED)
**Severity:** MEDIUM | **Status:** Fixed
**Location:** `src/bin/bal-server.rs`
**Description:** Network, txid, and content validation.
**Mitigation Applied:**
- Network validation: `NETWORKS.contains(&param.as_str())` before processing. Unknown networks return 404.
- Txid validation: `echo_search` requires exactly 64 ASCII hex characters. Non-hex or wrong length returns 400.
- XPub address caching: `get_all_addresses_by_xpub` loads all addresses once per batch (O(1) lookup), eliminating N+1 queries.
- Content-Length: Handled by actix-web `PayloadConfig` size limit.
**Regression Tests:** `tests/input_validation_tests.rs` (4 tests).
### 10. Information Leakage (MITIGATED)
**Severity:** LOW | **Status:** Mitigated
**Location:** Application logs
**Description:** Raw file logging (`valid_txs`/`invalid_txs`) has been removed. `info!`/`warn!` macros may still log txid and details in application logs.
**Mitigation (Operational):** Set production `RUST_LOG` to `warn` or higher. Log files restricted with `chmod 600`.
### 11. `bal-stats.rs.dontcompile` (REMOVED)
**Severity:** LOW | **Status:** Removed
**Description:** The broken HTML report generator file no longer exists in the source tree.
---
## Hardening Recommendations
### System-Level
1. Run as non-root user with systemd hardening (`ProtectSystem=full`, `NoNewPrivileges`, `PrivateDevices`, `MemoryDenyWriteExecute`).
2. Use firewall to block all inbound ports except HTTPS (443) and SSH (22).
3. Use VPN or Tor for `welist` connections if on public network.
4. Run in a container or chroot for isolation.
5. Enable SELinux or AppArmor profiles for the binaries.
6. Use read-only filesystem for the server binary.
### Application-Level
1. **Rate Limiting:** Implemented via `actix-governor` with per-endpoint token-bucket configuration.
2. **Input Validation:** Network enum check, txid hex validation, body size limits.
3. **HTTPS:** Via Nginx reverse proxy with Let's Encrypt.
4. **WAL Mode:** Enabled with retry logic for concurrent access.
5. **ZMQ Timeout:** 5-second receive timeout prevents infinite blocking.
6. **Transaction Size Limits:** Configurable via rate limiting and body size.
7. **ZMQ Retry:** Reconnect logic with timeout-based detection.
8. **Fee Limits:** Per-network `fixed_fee` configuration.
9. **Network Limits:** Only known networks accepted (bitcoin, testnet, testnet4, signet, regtest).
10. **Locktime Reasonableness:** Locktime compared against blockchain height and median time with threshold-based distinction.
---
## Regression Test Suite
| Test File | Tests | Coverage |
|-----------|-------|----------|
| `tests/sql_injection_tests.rs` | 3 | Parameterized queries, injection prevention |
| `tests/panic_regression_tests.rs` | 2 | Mutex poisoning recovery, NULL value handling |
| `tests/ssrf_tests.rs` | 4+ | URL validation, internal IP blocking |
| `tests/secret_leakage_tests.rs` | 3 | .gitignore, no tracked secrets, no hardcoded tokens |
| `tests/input_validation_tests.rs` | 4 | Address caching, network validation, txid hex validation |
| `tests/db_path_validation.rs` | 5 | Path traversal, forbidden dirs, symlinks, WAL pragma, valid paths |
| `src/validation.rs` (inline) | 8 | SSRF URL validation unit tests |