feat: implement security audit fixes - rate limiting and SSRF protection (Issue #265 PR #2)

This commit implements HIGH-02 (Rate Limiting) and HIGH-03 (SSRF Protection)
from the security audit, protecting against brute force attacks and
Server-Side Request Forgery.

Security Enhancements:
- Rate limiting: 20 attempts per 15 minutes per IP (configurable)
- SSRF protection: Three security modes (strict/moderate/permissive)
- DNS rebinding prevention
- Cloud metadata blocking in all modes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
czlonkowski
2025-10-06 15:40:07 +02:00
parent 9a00a99011
commit 06cbb40213
15 changed files with 1041 additions and 13 deletions

View File

@@ -65,6 +65,9 @@ docker run -d \
| `NODE_ENV` | Environment: `development` or `production` | `production` | No |
| `LOG_LEVEL` | Logging level: `debug`, `info`, `warn`, `error` | `info` | No |
| `NODE_DB_PATH` | Custom database path (v2.7.16+) | `/app/data/nodes.db` | No |
| `AUTH_RATE_LIMIT_WINDOW` | Rate limit window in ms (v2.16.3+) | `900000` (15 min) | No |
| `AUTH_RATE_LIMIT_MAX` | Max auth attempts per window (v2.16.3+) | `20` | No |
| `WEBHOOK_SECURITY_MODE` | SSRF protection: `strict`/`moderate`/`permissive` (v2.16.3+) | `strict` | No |
*Either `AUTH_TOKEN` or `AUTH_TOKEN_FILE` must be set for HTTP mode. If both are set, `AUTH_TOKEN` takes precedence.
@@ -283,7 +286,36 @@ docker ps --format "table {{.Names}}\t{{.Status}}"
docker inspect n8n-mcp | jq '.[0].State.Health'
```
## 🔒 Security Considerations
## 🔒 Security Features (v2.16.3+)
### Rate Limiting
Protects against brute force authentication attacks:
```bash
# Configure in .env or docker-compose.yml
AUTH_RATE_LIMIT_WINDOW=900000 # 15 minutes in milliseconds
AUTH_RATE_LIMIT_MAX=20 # 20 attempts per IP per window
```
### SSRF Protection
Prevents Server-Side Request Forgery when using webhook triggers:
```bash
# For production (blocks localhost + private IPs + cloud metadata)
WEBHOOK_SECURITY_MODE=strict
# For local development with local n8n instance
WEBHOOK_SECURITY_MODE=moderate
# For internal testing only (allows private IPs)
WEBHOOK_SECURITY_MODE=permissive
```
**Note:** Cloud metadata endpoints (169.254.169.254, metadata.google.internal, etc.) are ALWAYS blocked in all modes.
## 🔒 Authentication
### Authentication

View File

@@ -196,6 +196,41 @@ docker ps -a | grep n8n-mcp | grep Exited | awk '{print $1}' | xargs -r docker r
- Manually clean up containers periodically
- Consider using HTTP mode instead
### Webhooks to Local n8n Fail (v2.16.3+)
**Symptoms:**
- `n8n_trigger_webhook_workflow` fails with "SSRF protection" error
- Error message: "SSRF protection: Localhost access is blocked"
- Webhooks work from n8n UI but not from n8n-MCP
**Root Cause:** Default strict SSRF protection blocks localhost access to prevent attacks.
**Solution:** Use moderate security mode for local development
```bash
# For Docker run
docker run -d \
--name n8n-mcp \
-e MCP_MODE=http \
-e AUTH_TOKEN=your-token \
-e WEBHOOK_SECURITY_MODE=moderate \
-p 3000:3000 \
ghcr.io/czlonkowski/n8n-mcp:latest
# For Docker Compose - add to environment:
services:
n8n-mcp:
environment:
WEBHOOK_SECURITY_MODE: moderate
```
**Security Modes Explained:**
- `strict` (default): Blocks localhost + private IPs + cloud metadata (production)
- `moderate`: Allows localhost, blocks private IPs + cloud metadata (local development)
- `permissive`: Allows localhost + private IPs, blocks cloud metadata (testing only)
**Important:** Always use `strict` mode in production. Cloud metadata is blocked in all modes.
### n8n API Connection Issues
**Symptoms:**

View File

@@ -73,6 +73,13 @@ PORT=3000
# Optional: Enable n8n management tools
# N8N_API_URL=https://your-n8n-instance.com
# N8N_API_KEY=your-api-key-here
# Security Configuration (v2.16.3+)
# Rate limiting (default: 20 attempts per 15 minutes)
AUTH_RATE_LIMIT_WINDOW=900000
AUTH_RATE_LIMIT_MAX=20
# SSRF protection mode (default: strict)
# Use 'moderate' for local n8n, 'strict' for production
WEBHOOK_SECURITY_MODE=strict
EOF
# 2. Deploy with Docker
@@ -592,6 +599,67 @@ curl -H "Authorization: Bearer $AUTH_TOKEN" \
}
```
## 🔒 Security Features (v2.16.3+)
### Rate Limiting
Built-in rate limiting protects authentication endpoints from brute force attacks:
**Configuration:**
```bash
# Defaults (15 minutes window, 20 attempts per IP)
AUTH_RATE_LIMIT_WINDOW=900000 # milliseconds
AUTH_RATE_LIMIT_MAX=20
```
**Features:**
- Per-IP rate limiting with configurable window and max attempts
- Standard rate limit headers (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset)
- JSON-RPC formatted error responses
- Automatic IP tracking behind reverse proxies (requires TRUST_PROXY=1)
**Behavior:**
- First 20 attempts: Return 401 Unauthorized for invalid credentials
- Attempts 21+: Return 429 Too Many Requests with Retry-After header
- Counter resets after 15 minutes (configurable)
### SSRF Protection
Prevents Server-Side Request Forgery attacks when using webhook triggers:
**Three Security Modes:**
1. **Strict Mode (default)** - Production deployments
```bash
WEBHOOK_SECURITY_MODE=strict
```
- ✅ Block localhost (127.0.0.1, ::1)
- ✅ Block private IPs (10.x, 192.168.x, 172.16-31.x)
- ✅ Block cloud metadata (169.254.169.254, metadata.google.internal)
- ✅ DNS rebinding prevention
- 🎯 **Use for**: Cloud deployments, production environments
2. **Moderate Mode** - Local development with local n8n
```bash
WEBHOOK_SECURITY_MODE=moderate
```
- ✅ Allow localhost (for local n8n instances)
- ✅ Block private IPs
- ✅ Block cloud metadata
- ✅ DNS rebinding prevention
- 🎯 **Use for**: Development with n8n on localhost:5678
3. **Permissive Mode** - Internal networks only
```bash
WEBHOOK_SECURITY_MODE=permissive
```
- ✅ Allow localhost and private IPs
- ✅ Block cloud metadata (always blocked)
- ✅ DNS rebinding prevention
- 🎯 **Use for**: Internal testing (NOT for production)
**Important:** Cloud metadata endpoints are ALWAYS blocked in all modes for security.
## 🔒 Security Best Practices
### 1. Token Management

View File

@@ -105,6 +105,9 @@ These are automatically set by the Railway template:
| `CORS_ORIGIN` | `*` | Allow any origin |
| `HOST` | `0.0.0.0` | Listen on all interfaces |
| `PORT` | (Railway provides) | Don't set manually |
| `AUTH_RATE_LIMIT_WINDOW` | `900000` (15 min) | Rate limit window (v2.16.3+) |
| `AUTH_RATE_LIMIT_MAX` | `20` | Max auth attempts (v2.16.3+) |
| `WEBHOOK_SECURITY_MODE` | `strict` | SSRF protection mode (v2.16.3+) |
### Optional Variables
@@ -284,6 +287,32 @@ Since the Railway template uses a specific Docker image tag, updates are manual:
You could use the `latest` tag, but this may cause unexpected breaking changes.
## 🔒 Security Features (v2.16.3+)
Railway deployments include enhanced security features:
### Rate Limiting
- **Automatic brute force protection** - 20 attempts per 15 minutes per IP
- **Configurable limits** via `AUTH_RATE_LIMIT_WINDOW` and `AUTH_RATE_LIMIT_MAX`
- **Standard rate limit headers** for client awareness
### SSRF Protection
- **Default strict mode** blocks localhost, private IPs, and cloud metadata
- **Cloud metadata always blocked** (169.254.169.254, metadata.google.internal, etc.)
- **Use `moderate` mode only if** connecting to local n8n instance
**Security Configuration:**
```bash
# In Railway Variables tab:
WEBHOOK_SECURITY_MODE=strict # Production (recommended)
# or
WEBHOOK_SECURITY_MODE=moderate # If using local n8n with port forwarding
# Rate limiting (defaults are good for most use cases)
AUTH_RATE_LIMIT_WINDOW=900000 # 15 minutes
AUTH_RATE_LIMIT_MAX=20 # 20 attempts per IP
```
## 📝 Best Practices
1. **Always change the default AUTH_TOKEN immediately**