mirror of
https://github.com/Such-Software/smirk-backend-core.git
synced 2026-10-17 07:21:32 +02:00
fix: pre-ship audit remediation for auth identity, abuse control and retention
Fixes every confirmed backend finding from the v0.3.0 pre-ship review. Identity (the two that corrupt accounts): - nostr_register creates a row with pubkey_hash NULL, so that wallet's later /auth/extension call matched nothing, fell through the rotation path (which no client ever satisfies, since nothing sends rotation_signature) and minted a SECOND account. A fingerprint match on a NULL-pubkey_hash row now adopts the submitted pubkey_hash onto that row, but only when the row's on-file BTC key equals the submitted one, so a bare fingerprint (which check_restore discloses, and is therefore not a secret) still cannot claim an account. - The fingerprint-ownership check no longer short-circuits on returning_by_pubkey. It was skipped for returning users, so a fingerprint owned by another row got backfilled, violated the UNIQUE index, and 500'd that account on every subsequent login. - The rotation proof is verified over a distinct, instance- and target-bound message. It shared the login message, so a captured login signature was a replayable rotation proof against another instance. Abuse control: - The rate limiters key on the real client IP, honouring X-Forwarded-For only from a trusted proxy. Behind the TLS terminator every request looked like 127.0.0.1, so the whole internet shared one bucket and ~3 req/s 429'd every wallet unlock globally. - A PoW solution is single-use instead of replayable for the challenge TTL. - Delegated /verify is opt-in and rate-limited; it was an unauthenticated amplifier into Electrum, LWS and a full-genesis grin scan. - A grin scan with no start_height gets the same depth policy and PoW price as one that passes a height, instead of an unbounded free scan. Retention and logging: - The retention sweep is implemented AND scheduled. RETENTION_* was advertised and inert, which made the privacy policy's retention promise untrue. Zero means keep forever, and each statement is batched so a backlog drains over ticks rather than holding row locks. - login_events.ip_hash is no longer written, and legacy values are scrubbed: nothing ever read it, so it was retention without a purpose. - Tracing spans log user_id only, not the raw npub and username. - secret-scan.sh matches the coverage its comment claims. Also fixes the test suite, which did not compile on this commit: NewSession gained an id inc64cd9band two call sites were never updated. mint_session now binds one session_id for both the token and the row, since a different id there would silently recreate the bugc64cd9bfixed.
This commit is contained in:
+15
-4
@@ -18,11 +18,22 @@ else
|
||||
fi
|
||||
|
||||
# Secret shapes (not names), covering the classes this backend actually handles:
|
||||
# - PEM/OpenSSH/PGP private-key blocks and seed-phrase markers
|
||||
# - PEM/OpenSSH/PGP private-key blocks
|
||||
# - seed-phrase markers (mnemonic / seed phrase), any capitalisation
|
||||
# - nsec1... Nostr SECRET keys (bech32)
|
||||
# - a *_PEPPER / *_SALT (or admin key/secret) assigned a 32+ hex-char value, i.e.
|
||||
# an `openssl rand -hex 32` peppered secret pasted in cleartext
|
||||
PATTERNS='(-----BEGIN ([A-Z ]+ )?PRIVATE KEY-----|-----BEGIN PGP PRIVATE KEY|BEGIN OPENSSH PRIVATE KEY|\b(mnemonic|seed[_ ]?phrase)\b\s*[:=]|nsec1[0-9a-z]{20,}|\b[A-Z_]*(PEPPER|SALT|INTEGRITY_SECRET)[A-Z_]*\s*=\s*[0-9a-fA-F]{32,})'
|
||||
# - a secret-shaped env assignment given a 32+ hex-char value, i.e. an
|
||||
# `openssl rand -hex 32` value pasted in cleartext. The name alternation is
|
||||
# spelled out so it really does cover every secret this backend takes:
|
||||
# *_PEPPER, *_SALT, *_SECRET (incl. *_INTEGRITY_SECRET), *_PASSWORD, *_TOKEN,
|
||||
# *_API_KEY, *_ADMIN_KEY, *_HMAC_KEY, *_PRIVATE_KEY, *_SIGNING_KEY. A bare
|
||||
# *KEY* is NOT in the list on purpose: it would fire on ADMIN_PUBKEYS and
|
||||
# friends, whose values are public.
|
||||
#
|
||||
# NOT covered, and left to gitleaks rather than implied here: secret VALUES that
|
||||
# are not hex (base64 or random alphanumeric API keys, real passwords). Catching
|
||||
# those needs entropy heuristics, which in this tree would fire on every address,
|
||||
# hash and test vector and train people to ignore the scanner.
|
||||
PATTERNS='(-----BEGIN ([A-Z ]+ )?PRIVATE KEY-----|-----BEGIN PGP PRIVATE KEY|BEGIN OPENSSH PRIVATE KEY|\b([Mm]nemonic|MNEMONIC|[Ss]eed[_ ]?[Pp]hrase|SEED[_ ]?PHRASE)\b\s*[:=]|nsec1[0-9a-z]{20,}|\b[A-Z_]*(PEPPER|SALT|SECRET|PASSWORD|TOKEN|API_?KEY|ADMIN_KEY|HMAC_KEY|PRIVATE_KEY|SIGNING_KEY)[A-Z_]*\s*=\s*[0-9a-fA-F]{32,})'
|
||||
|
||||
fail=0
|
||||
for f in "${FILES[@]}"; do
|
||||
|
||||
Reference in New Issue
Block a user