# API Protection & Security

**Protection against external access and DDoS attacks on resource-intensive endpoints.**

---

## ✅ VERIFICATION STATUS

**Last Tested:** November 9, 2025
**Status:** ✅ **ALL PROTECTION MECHANISMS VERIFIED WORKING**

### Verified Test Results

| Test | Expected | Actual | Status |
|------|----------|--------|--------|
| External referer (evil.com) | 403 Forbidden | 403 Forbidden | ✅ PASS |
| Localhost referer | 200 OK | 200 OK | ✅ PASS |
| Production domain referer | 200 OK | 200 OK | ✅ PASS |
| External Origin header | 403 Forbidden | 403 Forbidden | ✅ PASS |
| No referer (development) | 200 OK | 200 OK | ✅ PASS |
| Rate limit (requests 1-3) | 200 OK | 200 OK | ✅ PASS |
| Rate limit (request 4+) | 429 Too Many | 429 Too Many | ✅ PASS |

**Protection Layers:** Origin checking + Rate limiting both working correctly.

---

## Overview

The CV website implements multiple layers of protection to prevent external sites from accessing the API and to protect against DDoS attacks on resource-intensive endpoints like PDF generation.

### Protection Layers

1. **Origin Checking** - Only allows requests from your domain
2. **Rate Limiting** - Prevents abuse even from allowed origins
3. **Production Restrictions** - Stricter rules in production environments

---

## 1. Origin Checking

**File:** `internal/middleware/security.go` (`OriginChecker` middleware)

### How It Works

The origin checker examines incoming HTTP requests and validates them against a whitelist of allowed domains. It checks two headers:

1. **Origin Header** - Set by browsers for CORS requests
2. **Referer Header** - Set by browsers for navigation requests

### Configuration

**Environment Variable:** `ALLOWED_ORIGINS`

```bash
# Development (default)
ALLOWED_ORIGINS=

# Production
ALLOWED_ORIGINS=yourdomain.com,www.yourdomain.com
```

### Behavior

| Environment | No Header | Localhost | Your Domain | External Domain |
|-------------|-----------|-----------|-------------|-----------------|
| **Development** | ✅ Allowed | ✅ Allowed | ✅ Allowed | ❌ Blocked |
| **Production** | ❌ Blocked (PDF) | ✅ Allowed | ✅ Allowed | ❌ Blocked |

**Production PDF Endpoint:**
- Requires `Origin` or `Referer` header
- Blocks direct URL access without headers
- Prevents bookmarking and external hotlinking

### Example Responses

**Allowed Request:**
```bash
curl -H "Referer: https://yourdomain.com/" http://localhost:1999/export/pdf?lang=en
# Status: 200 OK
# PDF file downloaded
```

**Blocked Request (External Domain):**
```bash
curl -H "Referer: https://externaldomain.com/" http://localhost:1999/export/pdf?lang=en
# Status: 403 Forbidden
# Response: Forbidden: External access not allowed
```

**Blocked Request (Production, No Headers):**
```bash
# In production with GO_ENV=production
curl http://yourdomain.com/export/pdf?lang=en
# Status: 403 Forbidden
# Response: Forbidden: Direct access not allowed
```

---

## 2. Rate Limiting

**File:** `internal/middleware/security.go` (`RateLimiter`)

### How It Works

The rate limiter tracks requests per IP address and enforces limits on resource-intensive endpoints.

**Current Configuration:**
- **Limit:** 3 requests per minute per IP
- **Window:** 1 minute
- **Applied to:** `/export/pdf` endpoint only

### Implementation

```go
// Create rate limiter for PDF endpoint
pdfRateLimiter := middleware.NewRateLimiter(3, 1*time.Minute)

// Apply to PDF endpoint
protectedPDFHandler := middleware.OriginChecker(
    pdfRateLimiter.Middleware(
        http.HandlerFunc(cvHandler.ExportPDF),
    ),
)
```

### Behavior

| Requests | Status | Response |
|----------|--------|----------|
| 1st request | ✅ 200 OK | PDF generated |
| 2nd request | ✅ 200 OK | PDF generated |
| 3rd request | ✅ 200 OK | PDF generated |
| 4th request (within 1 min) | ❌ 429 Too Many Requests | Rate limit exceeded |
| After 1 minute | ✅ 200 OK | Counter reset |

### Headers

**Rate Limit Exceeded Response:**
```
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: text/plain; charset=utf-8

Rate limit exceeded. Please try again later.
```

### IP Detection

The rate limiter detects client IP from:
1. `X-Forwarded-For` header (proxy/CDN)
2. `X-Real-IP` header (alternative proxy header)
3. `RemoteAddr` (direct connection)

**Supports reverse proxies:** Yes (Nginx, Cloudflare, etc.)

---

## 3. Combined Protection

The PDF endpoint has **both** origin checking and rate limiting applied:

```
Request → OriginChecker → RateLimiter → PDF Handler
```

**Protection Flow:**

1. **Check Origin/Referer**
   - If external domain → 403 Forbidden
   - If production + no headers → 403 Forbidden
   - Otherwise, continue

2. **Check Rate Limit**
   - If > 3 requests/minute → 429 Too Many Requests
   - Otherwise, continue

3. **Generate PDF**
   - Process request normally

---

## 4. Configuration Examples

### Development Environment

```bash
# .env
PORT=1999
HOST=localhost
GO_ENV=development
ALLOWED_ORIGINS=
```

**Behavior:**
- Allows `localhost` and `127.0.0.1`
- Allows requests without headers
- Rate limit: 3 PDF/min per IP

### Production Environment

```bash
# .env
PORT=1999
HOST=0.0.0.0
GO_ENV=production
ALLOWED_ORIGINS=yourdomain.com,www.yourdomain.com
```

**Behavior:**
- Only allows `yourdomain.com` and `www.yourdomain.com`
- Requires `Origin` or `Referer` header for PDF endpoint
- Rate limit: 3 PDF/min per IP

### Multiple Domains

```bash
# Support multiple domains (e.g., staging + production)
ALLOWED_ORIGINS=yourdomain.com,www.yourdomain.com,staging.yourdomain.com
```

---

## 5. Testing Protection

### Test Origin Checking

```bash
# ✅ Allowed (localhost in development)
curl http://localhost:1999/export/pdf?lang=en

# ✅ Allowed (with referer)
curl -H "Referer: http://localhost:1999/" http://localhost:1999/export/pdf?lang=en

# ❌ Blocked (external referer)
curl -H "Referer: https://evil.com/" http://localhost:1999/export/pdf?lang=en
# Expected: 403 Forbidden
```

### Test Rate Limiting

```bash
# Generate 4 PDFs quickly
for i in {1..4}; do
  echo "Request $i:"
  curl -w "Status: %{http_code}\n" -o /dev/null -s http://localhost:1999/export/pdf?lang=en
  sleep 1
done

# Expected output:
# Request 1: Status: 200
# Request 2: Status: 200
# Request 3: Status: 200
# Request 4: Status: 429
```

### Test Combined Protection

```bash
# Should be blocked by origin checker before rate limiter
for i in {1..5}; do
  curl -H "Referer: https://evil.com/" -w "Status: %{http_code}\n" -o /dev/null -s \
    http://localhost:1999/export/pdf?lang=en
done

# Expected: All requests get 403 (origin check fails immediately)
```

---

## 6. Monitoring & Logs

### Log Messages

**Origin Check Failure:**
```
# No specific log (returns 403 silently)
# Check server logs for 403 responses
```

**Rate Limit Exceeded:**
```
# No specific log (returns 429 silently)
# Monitor for frequent 429 responses
```

### Recommended Monitoring

1. **Track 403 responses** - Indicates potential attack attempts
2. **Track 429 responses** - Indicates rate limiting in effect
3. **Monitor PDF generation times** - Detect abuse patterns
4. **Alert on sustained high request rates** - DDoS detection

---

## 7. Customization

### Adjust Rate Limits

**File:** `main.go`

```go
// Current: 3 requests per minute
pdfRateLimiter := middleware.NewRateLimiter(3, 1*time.Minute)

// More restrictive: 5 per hour
pdfRateLimiter := middleware.NewRateLimiter(5, 1*time.Hour)

// Less restrictive: 10 per minute
pdfRateLimiter := middleware.NewRateLimiter(10, 1*time.Minute)
```

### Apply to Other Endpoints

```go
// Protect /cv endpoint
protectedCVHandler := middleware.OriginChecker(
    http.HandlerFunc(cvHandler.CVContent),
)
mux.Handle("/cv", protectedCVHandler)
```

### Disable Origin Checking (Not Recommended)

```go
// Apply only rate limiting (no origin check)
mux.Handle("/export/pdf", pdfRateLimiter.Middleware(
    http.HandlerFunc(cvHandler.ExportPDF),
))
```

---

## 8. Security Best Practices

### ✅ Recommended

1. **Set ALLOWED_ORIGINS in production** - Never run production without it
2. **Use HTTPS** - Prevents header spoofing
3. **Monitor 403/429 responses** - Detect attack patterns
4. **Consider CloudFlare** - Additional DDoS protection layer
5. **Log suspicious requests** - For forensic analysis

### ❌ Anti-Patterns

1. **Don't disable protection in production** - Always use origin checking
2. **Don't set rate limits too high** - PDF generation is expensive
3. **Don't trust IP addresses alone** - Use combined protection
4. **Don't expose internal endpoints** - Keep admin routes private

---

## 9. Production Deployment Checklist

Before deploying to production:

- [ ] Set `GO_ENV=production` in environment
- [ ] Configure `ALLOWED_ORIGINS` with your domain(s)
- [ ] Test origin checking with external domain
- [ ] Test rate limiting with rapid requests
- [ ] Verify HTTPS is enabled (prevents header spoofing)
- [ ] Set up monitoring for 403/429 responses
- [ ] Configure log retention for security analysis
- [ ] Test PDF generation under load
- [ ] Verify reverse proxy headers (X-Forwarded-For)
- [ ] Document allowed origins in runbook

---

## 10. Troubleshooting

### Problem: Legitimate users getting 403

**Cause:** ALLOWED_ORIGINS not configured correctly

**Solution:**
```bash
# Ensure all your domains are listed
ALLOWED_ORIGINS=yourdomain.com,www.yourdomain.com

# Check for typos (case-insensitive but must match exactly)
```

### Problem: Rate limit too restrictive

**Cause:** Legitimate users hitting limit

**Solution:**
```go
// Increase limit or window in main.go
pdfRateLimiter := middleware.NewRateLimiter(5, 1*time.Minute)
```

### Problem: Behind reverse proxy, rate limit not working

**Cause:** IP detection failing

**Solution:**
```nginx
# Ensure Nginx passes correct headers
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
```

### Problem: Origin header not being sent

**Cause:** Browser doesn't send Origin for same-origin requests

**Solution:** This is normal. The middleware checks Referer as fallback.

---

## 11. Attack Scenarios & Mitigation

### Scenario 1: DDoS via PDF Generation

**Attack:** External site hotlinks to `/export/pdf`, triggering many PDF generations

**Mitigation:**
1. ✅ Origin checker blocks external domains (403)
2. ✅ Rate limiter prevents >3 requests/min per IP (429)
3. ✅ Production mode requires headers (blocks direct access)

**Result:** Attack fails, server protected

### Scenario 2: Header Spoofing

**Attack:** Attacker spoofs `Referer` header to bypass origin check

**Mitigation:**
1. ⚠️ HTTPS prevents header modification in transit
2. ✅ Rate limiter still applies (3 req/min limit)
3. ✅ IP-based tracking prevents distributed spoofing

**Result:** Individual attacker limited to 3 req/min

### Scenario 3: Distributed Attack

**Attack:** Botnet with many IPs, each generating PDFs

**Mitigation:**
1. ✅ Each IP limited to 3 req/min
2. ✅ Origin checker blocks if no valid referer
3. 🔴 Consider CloudFlare for large-scale DDoS

**Result:** Slowed but not fully blocked (add CloudFlare)

---

## Summary

**Protection Enabled:** ✅ Origin Checking + Rate Limiting

**Endpoints Protected:**
- `/export/pdf` - Full protection (origin + rate limit)

**Endpoints Unprotected:**
- `/` - Public home page
- `/cv` - Public CV content
- `/health` - Public health check
- `/static/*` - Public static files

**Configuration:** Environment-based via `ALLOWED_ORIGINS`

**Production Ready:** Yes (after setting ALLOWED_ORIGINS)

---

**For questions or to adjust protection levels, modify:**
- `internal/middleware/security.go` - Origin checking and rate limiting logic
- `main.go` - Apply protection to additional endpoints
- `.env` - Configure ALLOWED_ORIGINS for your domain
