diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-01-14 13:40:33 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-01-14 13:43:40 +0000 |
| commit | 5897e4bccd41f1a9ebb01a11280cea929c93d2c0 (patch) | |
| tree | cbe4d2447312b7bc7653bef874b6fb23d60a0ede /docs/explanation/defensive-measures.md | |
| parent | 4c8f1813fada9ce2bfd371095b0721bff68173e3 (diff) | |
| parent | 2821578202d1313c23c30a5dbae39548822e3c55 (diff) | |
Add defensive relay features with rate limiting and connection limits
Implement defensive measures to protect against DoS attacks:
- Add explicit rate limits (500 subscriptions, 60 events/min per connection)
- Add total connection limit (default: 500, configurable via NGIT_MAX_CONNECTIONS)
- Update configuration across all 4 locations (src, nix, docs, .env.example)
Per-IP rate limiting deferred until abuse is detected in production or
implemented in rust-nostr relay-builder to benefit the entire Nostr ecosystem.
Documentation added explaining the defensive features and rationale.
Detailed analysis of other relay implementations preserved in commit history.
Diffstat (limited to 'docs/explanation/defensive-measures.md')
| -rw-r--r-- | docs/explanation/defensive-measures.md | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/docs/explanation/defensive-measures.md b/docs/explanation/defensive-measures.md new file mode 100644 index 0000000..51f7278 --- /dev/null +++ b/docs/explanation/defensive-measures.md | |||
| @@ -0,0 +1,165 @@ | |||
| 1 | # Defensive Measures & Rate Limiting | ||
| 2 | |||
| 3 | This document describes the defensive measures implemented in ngit-grasp to protect against abuse, spam, and denial-of-service attacks. | ||
| 4 | |||
| 5 | **Note:** A point-in-time analysis of defensive measures in other Nostr relays (strfry, nostr-rs-relay, khatru) was conducted to inform these design decisions. The analysis examined connection limits, rate limiting approaches, and per-IP enforcement strategies across the ecosystem. | ||
| 6 | |||
| 7 | ## Overview | ||
| 8 | |||
| 9 | ngit-grasp employs multiple layers of defense: | ||
| 10 | |||
| 11 | 1. **Connection & Subscription Limits** - Per-connection limits on subscriptions and event publishing | ||
| 12 | 2. **Content Filtering** - Blacklist/whitelist system for repositories and event authors | ||
| 13 | 3. **Event Validation** - Strict GRASP-01 protocol validation | ||
| 14 | 4. **Relay Health Management** - Intelligent handling of problematic remote relays | ||
| 15 | |||
| 16 | ## What's Implemented | ||
| 17 | |||
| 18 | ### Per-Connection Rate Limits | ||
| 19 | |||
| 20 | **Source:** Built-in to rust-nostr relay-builder | ||
| 21 | |||
| 22 | - **Subscription limit:** Max 500 concurrent subscriptions per connection | ||
| 23 | - **Event publishing limit:** Max 60 events per minute per connection | ||
| 24 | - **Subscription ID length:** Max 250 characters | ||
| 25 | - **Filter limit:** Max 500 results per query (default) | ||
| 26 | |||
| 27 | These limits prevent individual connections from overwhelming the relay. | ||
| 28 | |||
| 29 | ### Per-IP Connection Monitoring | ||
| 30 | |||
| 31 | **Source:** Custom ngit-grasp implementation | ||
| 32 | **Location:** `src/metrics/connection.rs` | ||
| 33 | |||
| 34 | - **Status:** Monitoring only (does NOT enforce limits) | ||
| 35 | - Tracks connections per IP address internally | ||
| 36 | - Flags IPs exceeding threshold (default: 10 connections) | ||
| 37 | - **Privacy:** IP addresses never exposed in Prometheus metrics, only aggregate counts | ||
| 38 | - Logs warnings when threshold exceeded | ||
| 39 | |||
| 40 | **Note on enforcement:** Per-IP connection limits are not built into rust-nostr relay-builder (tracks per WebSocket connection, not per IP). If abuse is detected via metrics, enforcement should be implemented as a PR to rust-nostr/relay-builder to benefit the entire Nostr ecosystem, rather than custom code in ngit-grasp. | ||
| 41 | |||
| 42 | ### Content Filtering (Blacklists/Whitelists) | ||
| 43 | |||
| 44 | **Source:** Custom ngit-grasp implementation | ||
| 45 | **Location:** `src/config.rs`, `src/nostr/builder.rs` | ||
| 46 | |||
| 47 | **Event Blacklist:** | ||
| 48 | - Block ALL events from specific authors (npubs) | ||
| 49 | - Takes precedence over all other validation | ||
| 50 | - Events never reach storage or purgatory | ||
| 51 | |||
| 52 | **Repository Blacklist:** | ||
| 53 | - Block specific repositories, developers, or identifiers | ||
| 54 | - Takes precedence over whitelists | ||
| 55 | - Three formats: `npub`, `npub/identifier`, `identifier` | ||
| 56 | |||
| 57 | **Repository Whitelist:** | ||
| 58 | - Curate which repositories are accepted (GRASP-01 mode) | ||
| 59 | - Only accept announcements that both list your service AND match whitelist | ||
| 60 | - Same three formats as blacklist | ||
| 61 | |||
| 62 | **Archive Whitelist (GRASP-05):** | ||
| 63 | - Mirror specific repositories even if they don't list your service | ||
| 64 | - Same three formats as blacklist | ||
| 65 | - Default: read-only mode when enabled | ||
| 66 | |||
| 67 | **Privacy:** Blacklists not advertised in NIP-11 metadata. | ||
| 68 | |||
| 69 | ### Event Validation Plugin System | ||
| 70 | |||
| 71 | **Source:** Built-in to rust-nostr relay-builder | ||
| 72 | **Implementation:** Custom GRASP-01 validation in `src/nostr/builder.rs` | ||
| 73 | |||
| 74 | - **WritePolicy trait:** Controls which events are accepted | ||
| 75 | - **QueryPolicy trait:** Controls which queries are allowed (not currently used) | ||
| 76 | - Access to client IP address for future per-IP rate limiting | ||
| 77 | - Modular sub-policies for different event types (announcements, state events, PRs) | ||
| 78 | |||
| 79 | ### Relay Health Management (GRASP-02 Sync) | ||
| 80 | |||
| 81 | **Source:** Custom ngit-grasp implementation | ||
| 82 | **Location:** `src/sync/health.rs` | ||
| 83 | |||
| 84 | **Exponential Backoff:** | ||
| 85 | - Failed connections trigger increasing delays: 5s → 10s → 20s → ... → 1 hour max | ||
| 86 | - Prevents hammering dead or slow relays | ||
| 87 | |||
| 88 | **Naughty List:** | ||
| 89 | - Tracks relays with persistent infrastructure issues (DNS, TLS, protocol errors) | ||
| 90 | - Separate from normal connection failures | ||
| 91 | - 12-hour expiration (configurable) | ||
| 92 | - Reduces retry frequency for broken relays | ||
| 93 | |||
| 94 | **Rate Limit Detection:** | ||
| 95 | - Detects when remote relay rate limits us | ||
| 96 | - Automatic 65-second cooldown | ||
| 97 | - Prevents hammering relays that tell us to slow down | ||
| 98 | |||
| 99 | **Domain Throttling (Git Data Fetching):** | ||
| 100 | - Max 5 concurrent requests per domain | ||
| 101 | - Max 30 requests per minute per domain | ||
| 102 | - Respectful rate limiting when fetching missing git data | ||
| 103 | |||
| 104 | ## What's NOT Implemented | ||
| 105 | |||
| 106 | ### Per-IP Rate Limiting | ||
| 107 | |||
| 108 | - **Per-IP connection limits:** Not enforced (only monitored) | ||
| 109 | - **Per-IP subscription limits:** Not supported | ||
| 110 | - **Per-IP event publishing limits:** Not supported | ||
| 111 | |||
| 112 | **Why:** rust-nostr relay-builder tracks limits per WebSocket connection, not per IP address. | ||
| 113 | |||
| 114 | **To implement:** Would require custom middleware/WritePolicy to aggregate across connections from the same IP. | ||
| 115 | |||
| 116 | ### Query Filtering | ||
| 117 | |||
| 118 | **Status:** QueryPolicy trait available but not currently used. | ||
| 119 | |||
| 120 | **Potential uses:** Rate limit queries per IP, block expensive queries, restrict access to certain event kinds. | ||
| 121 | |||
| 122 | ## Future Enhancements | ||
| 123 | |||
| 124 | ### Per-IP Rate Limiting | ||
| 125 | |||
| 126 | Per-IP connection and event rate limiting were considered but deferred until abuse is detected in production. The current protections (per-connection limits, total connection limit, content filtering) are sufficient for the git relay use case. | ||
| 127 | |||
| 128 | **Decision rationale:** The primary DoS vector is connection exhaustion, which is addressed by the total connection limit (`NGIT_MAX_CONNECTIONS`). Per-IP enforcement would require custom middleware in rust-nostr relay-builder (which currently tracks limits per WebSocket connection, not per IP). If abuse is detected via the per-IP monitoring metrics, enforcement should be implemented as a PR to rust-nostr/relay-builder to benefit the entire Nostr ecosystem. | ||
| 129 | |||
| 130 | **Related:** Git endpoint throttling (issue ff38) is a separate concern with different requirements. | ||
| 131 | |||
| 132 | ## Summary Table | ||
| 133 | |||
| 134 | | Feature | Status | Enforced? | Configurable? | | ||
| 135 | |---------|--------|-----------|---------------| | ||
| 136 | | **Per-Connection Limits** | | ||
| 137 | | Max subscriptions (500) | ✅ Active | Yes | No (relay-builder default) | | ||
| 138 | | Event rate limit (60/min) | ✅ Active | Yes | No (relay-builder default) | | ||
| 139 | | **Total Connection Limit** | | ||
| 140 | | Max connections (500) | ✅ Active | Yes | Yes (`NGIT_MAX_CONNECTIONS`) | | ||
| 141 | | **Per-IP Monitoring** | | ||
| 142 | | Connection tracking | ✅ Active | No (monitor only) | Threshold only | | ||
| 143 | | **Content Filtering** | | ||
| 144 | | Event blacklist | ✅ Active | Yes | Yes | | ||
| 145 | | Repository blacklist | ✅ Active | Yes | Yes | | ||
| 146 | | Repository whitelist | ✅ Active | Yes (if set) | Yes | | ||
| 147 | | Archive whitelist | ✅ Active | Yes (if set) | Yes | | ||
| 148 | | **Event Validation** | | ||
| 149 | | GRASP-01 validation | ✅ Active | Yes | Via WritePolicy | | ||
| 150 | | **Relay Sync Protection** | | ||
| 151 | | Exponential backoff | ✅ Active | Yes | Yes | | ||
| 152 | | Naughty list | ✅ Active | Yes | Yes (12h default) | | ||
| 153 | | Rate limit detection | ✅ Active | Yes | Automatic | | ||
| 154 | | Domain throttling | ✅ Active | Yes | Hardcoded (5/30) | | ||
| 155 | | **Not Implemented** | | ||
| 156 | | Per-IP connection limit | ⚠️ Deferred | No | - | | ||
| 157 | | Per-IP rate limiting | ⚠️ Deferred | No | - | | ||
| 158 | | Query filtering | ⚠️ Available | No | Not implemented | | ||
| 159 | |||
| 160 | ## Related Documentation | ||
| 161 | |||
| 162 | - [Configuration Reference](../reference/configuration.md) - All config options for defensive features | ||
| 163 | - [Monitoring Overview](monitoring.md) - Prometheus metrics for tracking abuse | ||
| 164 | - [GRASP-05 Archive](grasp-05-archive.md) - Archive whitelist details | ||
| 165 | - [Architecture](architecture.md) - Overall system design | ||