Files
nofx/api/crypto_handler.go
tinkle-community 1aea7abc38 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).
2026-06-05 22:08:26 +08:00

81 lines
2.4 KiB
Go

package api
import (
"net/http"
"nofx/config"
"nofx/crypto"
"github.com/gin-gonic/gin"
)
// CryptoHandler Encryption API handler
type CryptoHandler struct {
cryptoService *crypto.CryptoService
}
// NewCryptoHandler Creates encryption handler
func NewCryptoHandler(cryptoService *crypto.CryptoService) *CryptoHandler {
return &CryptoHandler{
cryptoService: cryptoService,
}
}
// ==================== Crypto Config Endpoint ====================
// HandleGetCryptoConfig Get crypto configuration
func (h *CryptoHandler) HandleGetCryptoConfig(c *gin.Context) {
cfg := config.Get()
c.JSON(http.StatusOK, gin.H{
"transport_encryption": cfg.TransportEncryption,
})
}
// ==================== Public Key Endpoint ====================
// HandleGetPublicKey Get server public key
func (h *CryptoHandler) HandleGetPublicKey(c *gin.Context) {
cfg := config.Get()
if !cfg.TransportEncryption {
c.JSON(http.StatusOK, gin.H{
"public_key": "",
"algorithm": "",
"transport_encryption": false,
})
return
}
publicKey := h.cryptoService.GetPublicKeyPEM()
c.JSON(http.StatusOK, gin.H{
"public_key": publicKey,
"algorithm": "RSA-OAEP-2048",
"transport_encryption": true,
})
}
// ==================== Encrypted Data Decryption ====================
//
// SECURITY: there is deliberately NO public decrypt endpoint. Transport
// encryption is one-directional — clients encrypt sensitive fields to the
// server's RSA public key and the authenticated config-update handlers
// (handleUpdateModelConfigs / handleUpdateExchangeConfigs / handleCreateExchange)
// decrypt them server-side via cryptoService.DecryptSensitiveData. Exposing a
// generic decrypt route would turn the server into a decryption oracle that any
// unauthenticated caller could use to recover the plaintext of a captured
// ciphertext, defeating the entire transport-encryption layer.
// ==================== Audit Log Query Endpoint ====================
// Audit log functionality removed, not needed in current simplified implementation
// ==================== Utility Functions ====================
// isValidPrivateKey Validate private key format
func isValidPrivateKey(key string) bool {
// EVM private key: 64 hex characters (optional 0x prefix)
if len(key) == 64 || (len(key) == 66 && key[:2] == "0x") {
return true
}
// TODO: Add validation for other chains
return false
}