Introduction
Rate limiting alone won't stop a determined attacker. Defense in depth with multiple layers protects your API from denial of service attacks.
Key Concepts
DDoS: Distributed Denial of Service—overwhelming your server with requests from many sources.
IP Blocking: Blocking requests from specific IP addresses.
WAF: Web Application Firewall—filters malicious traffic.
CDN: Content Delivery Network—absorbs traffic at the edge.
Real World Context
DDoS protection is critical for:
- E-commerce during sales events: Competitors or bots may try to crash your site
- SaaS applications: Service availability directly affects revenue and trust
- Public APIs: Open endpoints are easy targets for automated attacks
- Financial services: Downtime can result in regulatory penalties
Deep Dive
IP-Based Blocking
This middleware checks every incoming request against a set of blocked IPs stored in the cache. Blocked requests receive an immediate 403 response:
python# middleware.py class IPBlockMiddleware: def __init__(self, get_response): self.get_response = get_response self.blocked_ips = cache.get('blocked_ips', set()) def __call__(self, request): ip = get_client_ip(request) if ip in self.blocked_ips: return JsonResponse({'error': 'Blocked'}, status=403) return self.get_response(request) def block_ip(ip, duration=3600): blocked = cache.get('blocked_ips', set()) blocked.add(ip) cache.set('blocked_ips', blocked, duration)
The block_ip() function uses cache TTL to automatically unblock IPs after the specified duration, preventing permanent lockouts from temporary issues.
Automatic Blocking
This system automatically escalates from rate limiting to full IP blocking when a client repeatedly exceeds their quota:
pythondef check_and_block(request): ip = get_client_ip(request) key = f'violations:{ip}' violations = cache.get(key, 0) if violations >= 10: # 10 rate limit violations block_ip(ip, duration=3600) # Block for 1 hour return True return False def rate_limit_middleware(get_response): def middleware(request): if not rate_limiter.check(request): violations_key = f'violations:{get_client_ip(request)}' cache.set(violations_key, cache.get(violations_key, 0) + 1, 300) if check_and_block(request): return JsonResponse({'error': 'Blocked for abuse'}, status=403) return JsonResponse({'error': 'Rate limited'}, status=429) return get_response(request) return middleware
After 10 rate limit violations within 5 minutes (cache TTL = 300), the IP is blocked for one hour. This deters automated abuse while giving legitimate users a reasonable error recovery window.
Defense Layers
- CDN/Edge: Cloudflare, AWS CloudFront absorb traffic
- Load Balancer: Distribute traffic, basic rate limiting
- WAF: Block known attack patterns
- Application: Rate limiting, authentication
- Database: Connection pooling, query limits
Common Pitfalls
-
Relying only on application-level protection: Application rate limiting can't handle volumetric attacks. Use CDN/WAF services.
-
Blocking by IP alone: Attackers use botnets with thousands of IPs. IP blocking is insufficient against distributed attacks.
-
No incident response plan: Knowing what to do during an attack is as important as prevention.
Best Practices
- Use a CDN: Absorbs attack traffic at the edge.
- Implement at multiple layers: Don't rely on one defense.
- Monitor and alert: Detect attacks early.
- Have a runbook: Know what to do during an attack.
Summary
DDoS protection requires multiple layers. Use CDN/WAF services for edge protection, implement application-level rate limiting and blocking, and have monitoring and response procedures in place.
Code Examples
from django.core.cache import cache
from django.http import JsonResponse
class IPBlockMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
ip = request.META.get('REMOTE_ADDR')
if cache.get(f'blocked:{ip}'):
return JsonResponse({'error': 'Blocked'}, status=403)
return self.get_response(request)
def block_ip(ip, duration=3600):
cache.set(f'blocked:{ip}', True, duration)