fix(security): remove decrypt oracle, redact secret logs, harden auth, bump Go

Address multiple vulnerabilities found during security review:

- Remove unauthenticated POST /api/crypto/decrypt decryption oracle (route,
  handler, dead frontend helper) + regression test. Transport encryption is
  one-directional; the server never needs to decrypt arbitrary client payloads.
- Redact secrets in config-update logs: handler_ai_model/handler_exchange logged
  %+v of decrypted requests, leaking API keys / secret keys / passphrases /
  private keys. Use named types shared with the log sanitizer so the masking
  can never drift again; extend masking to passphrase + lighter_api_key_private_key.
- crypto: require a valid timestamp in DecryptPayload (a missing ts previously
  skipped replay protection entirely).
- crypto: EncryptedString.Value() now fails closed instead of silently
  persisting plaintext secrets when encryption errors.
- auth: per-IP token-bucket rate limiting on /login and /register against online
  brute-force; raise registration password minimum 6 -> 8; add dummy bcrypt
  compare on unknown-email login to close the user-enumeration timing channel.
- IDOR: getTraderFromQuery no longer falls back to the global in-memory trader
  map; trader access is strictly scoped to the authenticated caller.
- Bump Go 1.25.10 -> 1.25.11 to resolve reachable net/textproto and crypto/x509
  stdlib advisories (govulncheck now reports 0 affecting vulnerabilities).
This commit is contained in:
tinkle-community
2026-06-05 22:08:26 +08:00
parent 577a0918c3
commit 1aea7abc38
13 changed files with 406 additions and 152 deletions

View File

@@ -179,24 +179,12 @@ export class CryptoService {
return data.public_key || ''
}
static async decryptSensitiveData(
payload: EncryptedPayload
): Promise<string> {
const response = await fetch('/api/crypto/decrypt', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
})
if (!response.ok) {
throw new Error(`Decryption failed: ${response.statusText}`)
}
const result = await response.json()
return result.plaintext
}
// NOTE: there is intentionally no decryptSensitiveData() here. Transport
// encryption is one-directional: the client encrypts sensitive fields to the
// server's public key and the server decrypts them internally on the
// authenticated config endpoints. The server exposes no public decrypt route,
// so a client-side decrypt helper would be both useless and a security
// anti-pattern (it implied an unauthenticated decryption oracle existed).
}
// 生成混淆字符串(用于剪贴板混淆)