security: login rate limiting, fix health endpoint, harden error handling

- Fix health endpoint returning null time (use time.Now() instead of context value)
- Add LoginRateLimiter: 5 attempts per 15min window, 5min block on brute-force
- Apply rate limiting to login/register endpoints
- Move reset-password to authenticated routes (was unauthenticated — critical vuln)
- Limit response body sizes on proxy/external API calls (prevent memory exhaustion)
- Sanitize error messages in agent chat endpoint (don't leak internal errors)
- Record login success/failure for rate limiting tracking
This commit is contained in:
shinchan-zhai
2026-03-23 09:43:20 +08:00
parent 84758e2942
commit f28f0e340c
6 changed files with 160 additions and 12 deletions

View File

@@ -66,7 +66,7 @@ func (b *Brain) scanNews(seen map[string]bool) {
resp, err := b.http.Get("https://min-api.cryptocompare.com/data/v2/news/?lang=EN&sortOrder=latest")
if err != nil { return }
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
body, err := io.ReadAll(io.LimitReader(resp.Body, 1024*1024)) // 1MB limit
if err != nil { return }
var result struct {
@@ -138,7 +138,7 @@ func (b *Brain) sendBrief(hour int) {
for _, sym := range []string{"BTCUSDT", "ETHUSDT"} {
resp, err := b.http.Get(fmt.Sprintf("https://fapi.binance.com/fapi/v1/ticker/24hr?symbol=%s", sym))
if err != nil { continue }
body, readErr := io.ReadAll(resp.Body)
body, readErr := io.ReadAll(io.LimitReader(resp.Body, 64*1024)) // 64KB limit
resp.Body.Close()
if readErr != nil { continue }
var t map[string]string