fix(node): rate-limit relay HTTP endpoints
Relay routes were not wrapped in any guards — /relay/broadcast accepted unlimited writes from any IP, and /relay/inbox could be scraped at line rate. Combined with the per-recipient FIFO eviction (MailboxPerRecipientCap=500), an unauthenticated attacker could wipe a victim's real messages by spamming 500 garbage envelopes. This commit wraps writes in withSubmitTxGuards (10/s per IP + 256 KiB body cap) and reads in withReadLimit (20/s per IP) — the same limits already used for /api/tx and /api/address. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,12 +37,19 @@ type RelayConfig struct {
|
|||||||
// DELETE /relay/inbox/{envID} ?pub=<x25519hex>
|
// DELETE /relay/inbox/{envID} ?pub=<x25519hex>
|
||||||
// GET /relay/contacts ?pub=<ed25519hex>
|
// GET /relay/contacts ?pub=<ed25519hex>
|
||||||
func registerRelayRoutes(mux *http.ServeMux, rc RelayConfig) {
|
func registerRelayRoutes(mux *http.ServeMux, rc RelayConfig) {
|
||||||
mux.HandleFunc("/relay/send", relaySend(rc))
|
// Writes go through withSubmitTxGuards: per-IP rate limit (10/s, burst 20)
|
||||||
mux.HandleFunc("/relay/broadcast", relayBroadcast(rc))
|
// + 256 KiB body cap. Without these, a single attacker could spam
|
||||||
mux.HandleFunc("/relay/inbox/count", relayInboxCount(rc))
|
// 500 envelopes per victim in a few seconds and evict every real message
|
||||||
mux.HandleFunc("/relay/inbox/", relayInboxDelete(rc))
|
// via the mailbox FIFO cap.
|
||||||
mux.HandleFunc("/relay/inbox", relayInboxList(rc))
|
mux.HandleFunc("/relay/send", withSubmitTxGuards(relaySend(rc)))
|
||||||
mux.HandleFunc("/relay/contacts", relayContacts(rc))
|
mux.HandleFunc("/relay/broadcast", withSubmitTxGuards(relayBroadcast(rc)))
|
||||||
|
|
||||||
|
// Reads go through withReadLimit: per-IP rate limit (20/s, burst 40).
|
||||||
|
// Protects against inbox-scraping floods from a single origin.
|
||||||
|
mux.HandleFunc("/relay/inbox/count", withReadLimit(relayInboxCount(rc)))
|
||||||
|
mux.HandleFunc("/relay/inbox/", withReadLimit(relayInboxDelete(rc)))
|
||||||
|
mux.HandleFunc("/relay/inbox", withReadLimit(relayInboxList(rc)))
|
||||||
|
mux.HandleFunc("/relay/contacts", withReadLimit(relayContacts(rc)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// relayInboxList handles GET /relay/inbox?pub=<hex>[&since=<ts>][&limit=N]
|
// relayInboxList handles GET /relay/inbox?pub=<hex>[&since=<ts>][&limit=N]
|
||||||
|
|||||||
Reference in New Issue
Block a user