Skip to content

Add basic rate limiting to prevent DoS attacks #2

@melvincarvalho

Description

@melvincarvalho

Problem

The relay has no rate limiting, making it vulnerable to DoS attacks where a malicious client could send unlimited messages and overwhelm the server, especially problematic on resource-constrained mobile devices.

Solution

Implement a simple per-connection rate limiter that tracks message count per time window and rejects messages when the limit is exceeded.

Implementation Details

1. Add connection tracking Map after line 8:

const connections = new Map()  // Track per-connection stats

2. Add rate limiting logic in the message handler (after line 30):

socket.on('message', async (message) => {
  // Rate limiting check
  const now = Date.now()
  const stats = connections.get(socket) || { count: 0, lastReset: now }
  
  // Reset counter every minute
  if (now - stats.lastReset > 60000) {
    stats.count = 0
    stats.lastReset = now
  }
  
  stats.count++
  connections.set(socket, stats)
  
  // Enforce rate limit (100 messages per minute)
  if (stats.count > 100) {
    socket.send('["NOTICE", "Rate limit exceeded. Please slow down."]')
    return  // Don't process the message
  }
  
  // Continue with existing message processing...
  message = message?.toString()
  // ...
})

3. Add cleanup on connection close (after line 37):

socket.on('close', () => {
  subscribers.delete(socket)
  connections.delete(socket)  // Clean up rate limit tracking
})

4. Optional: Make rate limit configurable

const RATE_LIMIT = parseInt(process.env.RATE_LIMIT) || 100  // Messages per minute
const RATE_WINDOW = parseInt(process.env.RATE_WINDOW) || 60000  // Time window in ms

Testing

  1. Create a client that sends messages rapidly
  2. Verify that after 100 messages in a minute, further messages are rejected
  3. Wait 1 minute and verify the counter resets
  4. Verify memory is cleaned up when connections close

Impact

  • Lines of code: ~20 lines
  • Complexity: Minimal
  • Breaking changes: None (legitimate clients won't hit the limit)
  • Performance: O(1) operations only

Priority

HIGH - Essential for preventing abuse and ensuring stability on mobile devices.

Notes

  • 100 messages/minute is reasonable for Nostr relay usage
  • Could be enhanced later with per-IP limiting or more sophisticated algorithms
  • Consider adding metrics for monitoring rate limit hits

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or requestgood first issueGood for newcomers

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions