From 50000cd9d47681390c3c45feef98fe51c7b79a0f Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 14 Jan 2026 11:42:05 +0000 Subject: Add explicit rate limits and total connection limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Make RateLimit explicit in relay builder (500 subs, 60 events/min) - Add NGIT_MAX_CONNECTIONS config option (default: 500) - Update all 4 config locations (src, nix, docs, .env.example) - Fix documentation error: filter limit 5000→500 - Document Phase 2 deferral decision (per-IP enforcement) Addresses primary DoS vector (connection exhaustion) with minimal code. Per-IP rate limiting deferred until abuse detected in production. Related: issue ff38 (git endpoint throttling - separate concern) --- docs/explanation/defensive-measures.md | 211 +++++++++++++++++++++++++++++++++ docs/reference/configuration.md | 40 +++++++ 2 files changed, 251 insertions(+) create mode 100644 docs/explanation/defensive-measures.md (limited to 'docs') diff --git a/docs/explanation/defensive-measures.md b/docs/explanation/defensive-measures.md new file mode 100644 index 0000000..f7abc30 --- /dev/null +++ b/docs/explanation/defensive-measures.md @@ -0,0 +1,211 @@ +# Defensive Measures & Rate Limiting + +This document describes the defensive measures implemented in ngit-grasp to protect against abuse, spam, and denial-of-service attacks. + +## Overview + +ngit-grasp employs multiple layers of defense: + +1. **Connection & Subscription Limits** - Per-connection limits on subscriptions and event publishing +2. **Content Filtering** - Blacklist/whitelist system for repositories and event authors +3. **Event Validation** - Strict GRASP-01 protocol validation +4. **Relay Health Management** - Intelligent handling of problematic remote relays + +## What's Implemented + +### Per-Connection Rate Limits + +**Source:** Built-in to rust-nostr relay-builder + +- **Subscription limit:** Max 500 concurrent subscriptions per connection +- **Event publishing limit:** Max 60 events per minute per connection +- **Subscription ID length:** Max 250 characters +- **Filter limit:** Max 500 results per query (default) + +These limits prevent individual connections from overwhelming the relay. + +### Per-IP Connection Monitoring + +**Source:** Custom ngit-grasp implementation +**Location:** `src/metrics/connection.rs` + +- **Status:** Monitoring only (does NOT enforce limits) +- Tracks connections per IP address internally +- Flags IPs exceeding threshold (default: 10 connections) +- **Privacy:** IP addresses never exposed in Prometheus metrics, only aggregate counts +- Logs warnings when threshold exceeded + +**Future:** Could be extended to enforce per-IP connection limits. + +### Content Filtering (Blacklists/Whitelists) + +**Source:** Custom ngit-grasp implementation +**Location:** `src/config.rs`, `src/nostr/builder.rs` + +**Event Blacklist:** +- Block ALL events from specific authors (npubs) +- Takes precedence over all other validation +- Events never reach storage or purgatory + +**Repository Blacklist:** +- Block specific repositories, developers, or identifiers +- Takes precedence over whitelists +- Three formats: `npub`, `npub/identifier`, `identifier` + +**Repository Whitelist:** +- Curate which repositories are accepted (GRASP-01 mode) +- Only accept announcements that both list your service AND match whitelist +- Same three formats as blacklist + +**Archive Whitelist (GRASP-05):** +- Mirror specific repositories even if they don't list your service +- Same three formats as blacklist +- Default: read-only mode when enabled + +**Privacy:** Blacklists not advertised in NIP-11 metadata. + +### Event Validation Plugin System + +**Source:** Built-in to rust-nostr relay-builder +**Implementation:** Custom GRASP-01 validation in `src/nostr/builder.rs` + +- **WritePolicy trait:** Controls which events are accepted +- **QueryPolicy trait:** Controls which queries are allowed (not currently used) +- Access to client IP address for future per-IP rate limiting +- Modular sub-policies for different event types (announcements, state events, PRs) + +### Relay Health Management (GRASP-02 Sync) + +**Source:** Custom ngit-grasp implementation +**Location:** `src/sync/health.rs` + +**Exponential Backoff:** +- Failed connections trigger increasing delays: 5s → 10s → 20s → ... → 1 hour max +- Prevents hammering dead or slow relays + +**Naughty List:** +- Tracks relays with persistent infrastructure issues (DNS, TLS, protocol errors) +- Separate from normal connection failures +- 12-hour expiration (configurable) +- Reduces retry frequency for broken relays + +**Rate Limit Detection:** +- Detects when remote relay rate limits us +- Automatic 65-second cooldown +- Prevents hammering relays that tell us to slow down + +**Domain Throttling (Git Data Fetching):** +- Max 5 concurrent requests per domain +- Max 30 requests per minute per domain +- Respectful rate limiting when fetching missing git data + +## What's NOT Implemented + +### Per-IP Rate Limiting + +- **Per-IP connection limits:** Not enforced (only monitored) +- **Per-IP subscription limits:** Not supported +- **Per-IP event publishing limits:** Not supported + +**Why:** rust-nostr relay-builder tracks limits per WebSocket connection, not per IP address. + +**To implement:** Would require custom middleware/WritePolicy to aggregate across connections from the same IP. + +### Total Connection Limit + +**Status:** Supported by relay-builder but not currently configured in ngit-grasp. + +**To implement:** Add `max_connections(n)` to relay builder configuration. + +### Query Filtering + +**Status:** QueryPolicy trait available but not currently used. + +**Potential uses:** Rate limit queries per IP, block expensive queries, restrict access to certain event kinds. + +## Future Enhancements: Per-IP Rate Limiting (Deferred) + +### Decision: Defer Until Abuse Detected + +After comprehensive review (2026-01-14), we decided to defer per-IP rate limiting (Phase 2 & 3) until abuse patterns are detected in production. + +**Current protection (Phase 1):** +- Per-connection limits: 500 subscriptions, 60 events/min +- Total connection limit: 500 (configurable via `NGIT_MAX_CONNECTIONS`) +- Connection monitoring: Tracks IPs, flags abuse at 10 connections +- Content filtering: Event blacklist, repository blacklist/whitelist + +**Deferred features (Phase 2 & 3):** +- Per-IP connection enforcement (reject after 10 connections) +- Per-IP event rate limiting (reject after 100 events/min) + +### Rationale for Deferral + +1. **Config-only approach sufficient** - Total connection limit addresses primary DoS vector +2. **Git relay context** - Developer users less likely to abuse than general public +3. **Existing protections strong** - Per-connection limits + content filtering already robust +4. **Data-driven approach** - Monitor ConnectionTracker metrics, implement if needed +5. **Minimal maintenance** - Avoid custom rate limiting code until proven necessary + +### Implementation Path if Needed + +**Preferred approach:** Contribute to rust-nostr/relay-builder as PR +- Propose IP-based rate limiting as optional feature +- Let upstream maintain the code +- Benefits entire Nostr ecosystem + +**Fallback:** Implement in ngit-grasp +- Per-IP connection enforcement via actix middleware +- Per-IP event rate limiting via token bucket in WritePolicy +- See issue d6ee for detailed implementation plan + +### Monitoring for Abuse + +Watch these metrics to determine if Phase 2 is needed: +- `ngit_connections_per_ip` - IPs exceeding 10 connections +- `ngit_flagged_abusers` - IPs flagged by ConnectionTracker +- Event publishing patterns from single IPs + +**Trigger for Phase 2:** If abuse detected for 2-4 weeks after Phase 1 deployment + +### Related Work + +**Git endpoint throttling:** Separate concern, tracked in issue ff38 +- Git HTTP endpoints have different threat model (bandwidth/CPU intensive) +- Requires separate IP-based throttling (5 concurrent, 30/min per IP) +- No interaction with relay code + +## Summary Table + +| Feature | Status | Enforced? | Configurable? | +|---------|--------|-----------|---------------| +| **Per-Connection Limits** | +| Max subscriptions (500) | ✅ Active | Yes | No (relay-builder default) | +| Event rate limit (60/min) | ✅ Active | Yes | No (relay-builder default) | +| **Total Connection Limit** | +| Max connections (500) | ✅ Active | Yes | Yes (`NGIT_MAX_CONNECTIONS`) | +| **Per-IP Monitoring** | +| Connection tracking | ✅ Active | No (monitor only) | Threshold only | +| **Content Filtering** | +| Event blacklist | ✅ Active | Yes | Yes | +| Repository blacklist | ✅ Active | Yes | Yes | +| Repository whitelist | ✅ Active | Yes (if set) | Yes | +| Archive whitelist | ✅ Active | Yes (if set) | Yes | +| **Event Validation** | +| GRASP-01 validation | ✅ Active | Yes | Via WritePolicy | +| **Relay Sync Protection** | +| Exponential backoff | ✅ Active | Yes | Yes | +| Naughty list | ✅ Active | Yes | Yes (12h default) | +| Rate limit detection | ✅ Active | Yes | Automatic | +| Domain throttling | ✅ Active | Yes | Hardcoded (5/30) | +| **Deferred (Phase 2)** | +| Per-IP connection limit | ⚠️ Deferred | No | - | +| Per-IP rate limiting | ⚠️ Deferred | No | - | +| Query filtering | ⚠️ Available | No | Not implemented | + +## Related Documentation + +- [Configuration Reference](../reference/configuration.md) - All config options for defensive features +- [Monitoring Overview](monitoring.md) - Prometheus metrics for tracking abuse +- [GRASP-05 Archive](grasp-05-archive.md) - Archive whitelist details +- [Architecture](architecture.md) - Overall system design diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index 8b49297..c3001d3 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -925,6 +925,46 @@ Event blacklist does **not** affect NIP-11 metadata: --- +### Rate Limiting & DoS Protection + +#### `NGIT_MAX_CONNECTIONS` + +**Description:** Maximum total connections to the relay. Prevents connection exhaustion DoS attacks. +**Type:** Integer +**Default:** `500` +**Required:** No + +**Examples:** + +```bash +# Default: 500 connections +NGIT_MAX_CONNECTIONS=500 + +# Higher limit for large public relay +NGIT_MAX_CONNECTIONS=1000 + +# Lower limit for private relay +NGIT_MAX_CONNECTIONS=100 +``` + +**Notes:** + +- Limits total concurrent WebSocket connections to the relay +- Prevents connection exhaustion attacks +- Works in conjunction with per-connection limits (500 subscriptions, 60 events/min) +- When limit is reached, new connections are rejected +- Existing connections continue to work normally + +**Related Limits:** + +Per-connection limits (built-in to relay-builder, not configurable): +- Max subscriptions per connection: 500 +- Max events per minute per connection: 60 +- Max subscription ID length: 250 characters +- Max results per filter: 500 + +--- + ### Logging Configuration #### `RUST_LOG` -- cgit v1.2.3