-
-
Notifications
You must be signed in to change notification settings - Fork 6
security: harden attestation endpoint against replay and spoofing #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Scottcjn
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review: Attestation Endpoint Hardening (PR #3)
@BuilderFred - Good security additions. The rate limiting and nonce validation are real improvements. Some issues to address:
Issues
1. Nonce validation references non-existent table
row = c.execute("SELECT expires_at FROM nonces WHERE nonce = ?", (nonce,)).fetchone()There's no CREATE TABLE IF NOT EXISTS nonces in the init_db() changes. The nonces table doesn't exist in the schema — you added tickets but the code references nonces. This will crash at runtime.
2. Breaking change: nonce now required
if not nonce:
return jsonify({"error": "missing_nonce"}), 401Existing miners don't submit pre-fetched nonces from a server challenge. They generate their own nonce (timestamp-based) in the attestation payload. This change would reject ALL current miners immediately. You need backward compatibility:
- Accept miner-generated nonces (current behavior) as a fallback
- Only enforce server-issued nonces when the miner includes a challenge token
3. Rate limit memory leak
ATTEST_RATE_LIMIT dict grows unbounded. Old entries are reset when accessed, but if a key is never accessed again it stays forever. Add periodic cleanup:
# In check_rate_limit, periodically purge expired entries
if len(ATTEST_RATE_LIMIT) > 10000:
now = time.time()
ATTEST_RATE_LIMIT = {k: v for k, v in ATTEST_RATE_LIMIT.items() if v[1] > now}4. Schema changes need migration path
You changed epoch_state and balances schemas (added columns). CREATE TABLE IF NOT EXISTS won't add columns to existing tables. Need ALTER TABLE fallbacks for existing databases:
try:
c.execute("ALTER TABLE epoch_state ADD COLUMN settled INTEGER DEFAULT 0")
except: pass # Column already exists5. IP rate limiting with X-Forwarded-For
ip = request.headers.get("X-Forwarded-For", request.remote_addr)X-Forwarded-For is client-controlled when there's no trusted proxy. An attacker can rotate this header to bypass IP rate limiting. Should parse only the rightmost trusted proxy entry, or use request.remote_addr when there's no trusted reverse proxy list.
What's Good
- Rate limiting on both IP and miner ID is the right approach
- Nonce-based replay prevention is the right direction
- New security tables (blocked_wallets, hardware_bindings, miner_macs, etc.) are useful
- Code is clean and well-structured
Fix the nonces table creation, backward compatibility with existing miners, and the memory leak. Those are the blockers.
Also: your node at 27.145.146.131:8099 is unreachable (timed out on HTTP, HTTPS, and alternate ports). Is the firewall configured?
|
@BuilderFred Here's the full list of fixes needed before this can merge. Address all of these and push updated commits: 1. Create the
|
|
@BuilderFred Here's the full checklist of fixes needed before this can merge. Address all of these and push updated commits: Fix List1. Create the
|
Fixes Scottcjn/rustchain-bounties#3.
This PR implements the following security hardenings for the hardware attestation endpoint:
blocked_walletsandhardware_bindings) that caused 500 errors during attestation.