Skip to content

Commit 8e375f8

Browse files
authored
Merge pull request #49 from deepesh224-ux/feature/wishlist-api
feat(security): implement rate limiting and enhanced CORS configuration
2 parents c557ba1 + 01d8203 commit 8e375f8

6 files changed

Lines changed: 499 additions & 9 deletions

File tree

RATE_LIMITING_CORS.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Rate Limiting and CORS Configuration
2+
3+
## Overview
4+
This implementation provides comprehensive rate limiting and CORS configuration for the API Gateway to prevent brute-force attacks and ensure proper cross-origin resource sharing.
5+
6+
## Features Implemented
7+
8+
### 1. Rate Limiting
9+
- **General API**: 50 requests/minute (production), 100 requests/minute (development)
10+
- **Authentication**: 5 attempts per 15 minutes
11+
- **Strict Operations**: 10 requests per minute
12+
- **Progressive Slowdown**: Delays after 20 requests in 15 minutes
13+
14+
### 2. CORS Configuration
15+
- **Preflight Support**: Handles OPTIONS requests correctly
16+
- **Origin Validation**: Allows specific frontend domains
17+
- **Credentials**: Supports cookies and authorization headers
18+
- **Development Mode**: Allows localhost origins in development
19+
20+
### 3. Security Headers
21+
- **Helmet**: Comprehensive security headers
22+
- **CSP**: Content Security Policy
23+
- **HSTS**: HTTP Strict Transport Security
24+
- **XSS Protection**: Cross-site scripting protection
25+
26+
## API Endpoints
27+
28+
### Rate Limiting Test
29+
```bash
30+
# Test rate limiting (limited to 10 requests/minute)
31+
GET /api/test-security/rate-limit
32+
```
33+
34+
### CORS Test
35+
```bash
36+
# Test CORS configuration
37+
GET /api/test-security/cors
38+
39+
# Test CORS preflight
40+
OPTIONS /api/test-security/cors
41+
```
42+
43+
### Security Headers Test
44+
```bash
45+
# Test security headers
46+
GET /api/test-security/security-headers
47+
```
48+
49+
## Configuration
50+
51+
### Environment Variables
52+
```bash
53+
NODE_ENV=production # Enables stricter rate limits
54+
JWT_SECRET=your-secret-key
55+
```
56+
57+
### Rate Limits
58+
- **General**: 50/min (prod), 100/min (dev)
59+
- **Auth**: 5 attempts per 15 minutes
60+
- **Strict**: 10 requests per minute
61+
- **Speed Limit**: 20 requests, then 500ms delay
62+
63+
### CORS Origins
64+
- `http://localhost:3000` (React)
65+
- `http://localhost:5173` (Vite)
66+
- `http://localhost:8080` (Vue)
67+
- Production domains (to be added)
68+
69+
## Testing
70+
71+
### 1. Rate Limiting Test
72+
```bash
73+
# Make multiple requests to test rate limiting
74+
for i in {1..15}; do
75+
curl -w "%{http_code}\n" http://localhost:5000/api/test-security/rate-limit
76+
done
77+
```
78+
79+
### 2. CORS Test
80+
```bash
81+
# Test from browser console
82+
fetch('http://localhost:5000/api/test-security/cors', {
83+
method: 'GET',
84+
headers: {
85+
'Content-Type': 'application/json',
86+
},
87+
})
88+
.then(response => response.json())
89+
.then(data => console.log(data));
90+
```
91+
92+
### 3. Preflight Test
93+
```bash
94+
# Test CORS preflight
95+
curl -X OPTIONS \
96+
-H "Origin: http://localhost:3000" \
97+
-H "Access-Control-Request-Method: POST" \
98+
-H "Access-Control-Request-Headers: Content-Type" \
99+
http://localhost:5000/api/test-security/cors
100+
```
101+
102+
## Error Responses
103+
104+
### Rate Limit Exceeded
105+
```json
106+
{
107+
"success": false,
108+
"message": "Too many requests from this IP, please try again later.",
109+
"retryAfter": "1 minute"
110+
}
111+
```
112+
113+
### CORS Error
114+
```json
115+
{
116+
"success": false,
117+
"message": "CORS policy violation: Origin not allowed",
118+
"origin": "http://disallowed-origin.com"
119+
}
120+
```
121+
122+
## Security Features
123+
124+
1. **Brute Force Protection**: Stricter limits on auth endpoints
125+
2. **Progressive Delays**: Slows down repeated requests
126+
3. **IP-based Limiting**: Tracks requests per IP address
127+
4. **Origin Validation**: Only allows trusted domains
128+
5. **Security Headers**: Comprehensive security headers via Helmet
129+
130+
## Production Considerations
131+
132+
1. **Redis Store**: Consider using Redis for distributed rate limiting
133+
2. **Whitelist**: Add trusted IPs for higher limits
134+
3. **Monitoring**: Implement rate limit monitoring
135+
4. **Custom Messages**: Customize error messages per endpoint
136+
5. **Bypass Options**: Add bypass mechanisms for admin users
137+
138+
## Files Created
139+
- `src/middleware/rateLimiter.middleware.js` - Rate limiting configuration
140+
- `src/middleware/cors.middleware.js` - CORS configuration
141+
- `src/config/app.config.js` - Environment configuration
142+
- `src/routes/test-security.routes.js` - Test endpoints

src/app.js

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
11
import express from 'express';
2-
import cors from 'cors';
32
import passport from './config/passport.config.js';
43
import productRoutes from './routes/product.routes.js';
54
import cartRoutes from './routes/cart.routes.js';
65
import collectionRoutes from './routes/collection.routes.js';
76
import wishlistRoutes from './routes/wishlist.routes.js';
87
import testRoutes from './routes/test.routes.js';
8+
import testSecurityRoutes from './routes/test-security.routes.js';
99
import authRoutes from './routes/auth.routes.js';
1010
import errorHandler from './middleware/error-handler.middleware.js';
11-
import notFound from './middleware/notFound.middleware.js'
12-
import cookieParser from 'cookie-parser';
13-
11+
import notFound from './middleware/notFound.middleware.js';
12+
import { corsMiddleware, securityHeaders, corsErrorHandler } from './middleware/cors.middleware.js';
13+
import { generalRateLimit, authRateLimit, speedLimiter, strictRateLimit } from './middleware/rateLimiter.middleware.js';
1414
const app = express();
1515

16-
app.use(cors());
17-
app.use(express.json());
18-
app.use(cookieParser());
16+
// Security middleware (must be first)
17+
app.use(securityHeaders);
18+
19+
// CORS middleware
20+
app.use(corsMiddleware);
21+
22+
// Body parsing middleware
23+
app.use(express.json({ limit: '10mb' }));
24+
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
25+
26+
// Rate limiting middleware
27+
app.use(generalRateLimit);
28+
app.use(speedLimiter);
1929

2030
// Initialize Passport
2131
app.use(passport.initialize());
@@ -24,16 +34,23 @@ app.get('/',(req,res)=>{
2434
res.send("Welcome to Homepage");
2535
})
2636

27-
// Routes
37+
// Routes with specific rate limiting
2838
app.use('/api/products', productRoutes);
2939
app.use('/api/cart', cartRoutes);
3040
app.use('/api/collections', collectionRoutes);
3141
app.use('/api/wishlist', wishlistRoutes);
3242
app.use('/api/test', testRoutes);
33-
app.use('/auth', authRoutes);
43+
app.use('/api/test-security', testSecurityRoutes);
44+
45+
// Auth routes with stricter rate limiting
46+
app.use('/auth', authRateLimit, authRoutes);
47+
48+
// CORS error handler
49+
app.use(corsErrorHandler);
3450

3551
// Middleware for not found 404
3652
app.use(notFound);
53+
3754
// Global error handler (should be last)
3855
app.use(errorHandler);
3956

src/config/app.config.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/**
2+
* Environment configuration for rate limiting and CORS
3+
*/
4+
5+
export const config = {
6+
// Rate limiting configuration
7+
rateLimit: {
8+
// General API rate limits
9+
general: {
10+
windowMs: 60 * 1000, // 1 minute
11+
max: process.env.NODE_ENV === 'production' ? 50 : 100, // 50 in prod, 100 in dev
12+
},
13+
// Authentication rate limits (stricter)
14+
auth: {
15+
windowMs: 15 * 60 * 1000, // 15 minutes
16+
max: 5, // 5 attempts per 15 minutes
17+
},
18+
// Strict rate limits for sensitive operations
19+
strict: {
20+
windowMs: 60 * 1000, // 1 minute
21+
max: 10, // 10 requests per minute
22+
},
23+
// Speed limiter configuration
24+
speedLimit: {
25+
windowMs: 15 * 60 * 1000, // 15 minutes
26+
delayAfter: 20, // Allow 20 requests per 15 minutes at full speed
27+
delayMs: 500, // Add 500ms delay per request after delayAfter
28+
maxDelayMs: 20000, // Maximum delay of 20 seconds
29+
},
30+
},
31+
32+
// CORS configuration
33+
cors: {
34+
// Allowed origins
35+
allowedOrigins: [
36+
'http://localhost:3000', // React dev server
37+
'http://localhost:3001', // Alternative React port
38+
'http://localhost:5173', // Vite dev server
39+
'http://localhost:8080', // Vue dev server
40+
'http://127.0.0.1:3000', // Localhost alternative
41+
'http://127.0.0.1:5173', // Vite localhost alternative
42+
// Add production domains here
43+
// 'https://yourdomain.com',
44+
// 'https://www.yourdomain.com',
45+
],
46+
// Additional CORS settings
47+
credentials: true,
48+
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
49+
allowedHeaders: [
50+
'Origin',
51+
'X-Requested-With',
52+
'Content-Type',
53+
'Accept',
54+
'Authorization',
55+
'Cache-Control',
56+
'Pragma',
57+
],
58+
exposedHeaders: [
59+
'X-Total-Count',
60+
'X-Page-Count',
61+
'X-Current-Page',
62+
],
63+
},
64+
65+
// Security configuration
66+
security: {
67+
// Content Security Policy
68+
csp: {
69+
directives: {
70+
defaultSrc: ["'self'"],
71+
styleSrc: ["'self'", "'unsafe-inline'"],
72+
scriptSrc: ["'self'"],
73+
imgSrc: ["'self'", "data:", "https:"],
74+
},
75+
},
76+
// HSTS configuration
77+
hsts: {
78+
maxAge: 31536000, // 1 year
79+
includeSubDomains: true,
80+
preload: true,
81+
},
82+
},
83+
84+
// Request size limits
85+
requestLimits: {
86+
json: '10mb',
87+
urlencoded: '10mb',
88+
},
89+
};
90+
91+
export default config;

src/middleware/cors.middleware.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import cors from 'cors';
2+
import helmet from 'helmet';
3+
4+
/**
5+
* CORS configuration for frontend integration
6+
* Handles preflight requests and allows specific origins
7+
*/
8+
9+
// Allowed origins for CORS
10+
const allowedOrigins = [
11+
'http://localhost:3000', // React dev server
12+
'http://localhost:3001', // Alternative React port
13+
'http://localhost:5173', // Vite dev server
14+
'http://localhost:8080', // Vue dev server
15+
'http://127.0.0.1:3000', // Localhost alternative
16+
'http://127.0.0.1:5173', // Vite localhost alternative
17+
// Add production domains here
18+
// 'https://yourdomain.com',
19+
// 'https://www.yourdomain.com',
20+
];
21+
22+
// CORS options
23+
const corsOptions = {
24+
origin: (origin, callback) => {
25+
// Allow requests with no origin (mobile apps, Postman, etc.)
26+
if (!origin) return callback(null, true);
27+
28+
// Check if origin is in allowed list
29+
if (allowedOrigins.includes(origin)) {
30+
callback(null, true);
31+
} else {
32+
// In development, allow any localhost origin
33+
if (process.env.NODE_ENV !== 'production' && origin.includes('localhost')) {
34+
callback(null, true);
35+
} else {
36+
callback(new Error('Not allowed by CORS'));
37+
}
38+
}
39+
},
40+
credentials: true, // Allow cookies and authorization headers
41+
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
42+
allowedHeaders: [
43+
'Origin',
44+
'X-Requested-With',
45+
'Content-Type',
46+
'Accept',
47+
'Authorization',
48+
'Cache-Control',
49+
'Pragma',
50+
],
51+
exposedHeaders: [
52+
'X-Total-Count',
53+
'X-Page-Count',
54+
'X-Current-Page',
55+
],
56+
optionsSuccessStatus: 200, // Some legacy browsers choke on 204
57+
preflightContinue: false, // Pass the CORS preflight response to the next handler
58+
};
59+
60+
// Security headers configuration
61+
export const securityHeaders = helmet({
62+
contentSecurityPolicy: {
63+
directives: {
64+
defaultSrc: ["'self'"],
65+
styleSrc: ["'self'", "'unsafe-inline'"],
66+
scriptSrc: ["'self'"],
67+
imgSrc: ["'self'", "data:", "https:"],
68+
},
69+
},
70+
crossOriginEmbedderPolicy: false, // Disable for API compatibility
71+
hsts: {
72+
maxAge: 31536000,
73+
includeSubDomains: true,
74+
preload: true,
75+
},
76+
});
77+
78+
// CORS middleware
79+
export const corsMiddleware = cors(corsOptions);
80+
81+
// CORS error handler
82+
export const corsErrorHandler = (err, req, res, next) => {
83+
if (err.message === 'Not allowed by CORS') {
84+
res.status(403).json({
85+
success: false,
86+
message: 'CORS policy violation: Origin not allowed',
87+
origin: req.headers.origin,
88+
});
89+
} else {
90+
next(err);
91+
}
92+
};
93+
94+
export default {
95+
corsMiddleware,
96+
securityHeaders,
97+
corsErrorHandler,
98+
corsOptions,
99+
};

0 commit comments

Comments
 (0)