-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathjavascript-insecure-design.mdc
More file actions
491 lines (416 loc) · 20.1 KB
/
javascript-insecure-design.mdc
File metadata and controls
491 lines (416 loc) · 20.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
---
description: Detect and prevent insecure design patterns in JavaScript applications as defined in OWASP Top 10:2021-A04
globs: **/*.js, **/*.jsx, **/*.ts, **/*.tsx, !**/node_modules/**, !**/dist/**, !**/build/**, !**/coverage/**
---
# JavaScript Insecure Design (OWASP A04:2021)
<rule>
name: javascript_insecure_design
description: Detect and prevent insecure design patterns in JavaScript applications as defined in OWASP Top 10:2021-A04
actions:
- type: enforce
conditions:
# Pattern 1: Lack of Rate Limiting
- pattern: "app\\.(?:get|post|put|delete|patch)\\([^)]*?\\)\\s*(?!.*(?:rateLimiter|limiter|throttle|rateLimit))"
location: "(?:routes|api|controllers)"
message: "Potential lack of rate limiting in API endpoint. Consider implementing rate limiting to prevent abuse."
# Pattern 2: Insecure Direct Object Reference (IDOR)
- pattern: "(?:findById|getById|findOne)\\([^)]*?(?:req\\.|request\\.|params\\.|query\\.|body\\.|user\\.|input\\.|form\\.)[^)]*?\\)\\s*(?!.*(?:authorization|permission|access|canAccess|isAuthorized|checkPermission))"
location: "(?:routes|api|controllers)"
message: "Potential Insecure Direct Object Reference (IDOR) vulnerability. Implement proper authorization checks before accessing objects by ID."
# Pattern 3: Lack of Input Validation
- pattern: "(?:req\\.|request\\.|params\\.|query\\.|body\\.|user\\.|input\\.|form\\.)[a-zA-Z0-9_]+\\s*(?!.*(?:validate|sanitize|check|schema|joi|yup|zod|validator|isValid))"
location: "(?:routes|api|controllers)"
message: "Potential lack of input validation. Implement proper validation for all user inputs."
# Pattern 4: Hardcoded Business Logic
- pattern: "if\\s*\\([^)]*?(?:role\\s*===\\s*['\"]admin['\"]|isAdmin\\s*===\\s*true|user\\.role\\s*===\\s*['\"]admin['\"])\\s*\\)"
message: "Hardcoded business logic for authorization. Consider using a more flexible role-based access control system."
# Pattern 5: Lack of Proper Error Handling
- pattern: "catch\\s*\\([^)]*?\\)\\s*\\{[^}]*?(?:console\\.(?:log|error))[^}]*?\\}"
negative_pattern: "(?:res\\.status|next\\(err|next\\(error|errorHandler)"
message: "Improper error handling. Avoid only logging errors without proper handling or user feedback."
# Pattern 6: Insecure Authentication Design
- pattern: "(?:password|token|secret|key)\\s*===\\s*(?:req\\.|request\\.|params\\.|query\\.|body\\.|user\\.|input\\.|form\\.)"
message: "Insecure authentication design. Avoid direct string comparison for passwords or tokens."
# Pattern 7: Lack of Proper Logging
- pattern: "app\\.(?:get|post|put|delete|patch)\\([^)]*?\\)\\s*(?!.*(?:log|logger|winston|bunyan|morgan|audit))"
location: "(?:routes|api|controllers)"
message: "Lack of proper logging in API endpoint. Implement logging for security-relevant events."
# Pattern 8: Insecure Defaults
- pattern: "new\\s+(?:Session|Cookie|JWT)\\([^)]*?\\{[^}]*?(?:secure\\s*:\\s*false|httpOnly\\s*:\\s*false|sameSite\\s*:\\s*['\"]none['\"])"
message: "Insecure default configuration. Avoid setting secure:false, httpOnly:false, or sameSite:'none' for cookies or sessions."
# Pattern 9: Lack of Proper Access Control
- pattern: "router\\.(?:get|post|put|delete|patch)\\([^)]*?\\)\\s*(?!.*(?:authenticate|authorize|requireAuth|isAuthenticated|checkAuth|verifyToken|passport\\.authenticate))"
location: "(?:routes|api|controllers)"
message: "Potential lack of access control in route definition. Implement proper authentication and authorization middleware."
# Pattern 10: Insecure File Operations
- pattern: "(?:fs\\.(?:readFile|writeFile|appendFile|readdir|stat|access|open|unlink)|require)\\([^)]*?(?:(?:\\+|\\$\\{|\\`)[^)]*?(?:__dirname|__filename|process\\.cwd\\(\\)|path\\.(?:resolve|join)))"
negative_pattern: "path\\.normalize|path\\.resolve|path\\.join"
message: "Insecure file operations. Use path.normalize() and validate file paths to prevent directory traversal attacks."
# Pattern 11: Lack of Proper Secrets Management
- pattern: "(?:apiKey|secret|password|token|credentials)\\s*=\\s*(?:process\\.env\\.[A-Z_]+|config\\.[a-zA-Z0-9_]+|['\"][^'\"]+['\"])"
negative_pattern: "(?:vault|secretsManager|keyVault|secretClient)"
message: "Insecure secrets management. Consider using a dedicated secrets management solution instead of environment variables or configuration files."
# Pattern 12: Insecure Randomness
- pattern: "Math\\.random\\(\\)"
location: "(?:auth|security|token|password|key|iv|nonce|salt)"
message: "Insecure randomness. Use crypto.randomBytes() or a similar cryptographically secure random number generator for security-sensitive operations."
# Pattern 13: Lack of Proper Input Sanitization for Templates
- pattern: "(?:template|render|compile|ejs\\.render|handlebars\\.compile|pug\\.render)\\([^)]*?(?:(?:\\+|\\$\\{|\\`)[^)]*?(?:req\\.|request\\.|params\\.|query\\.|body\\.|user\\.|input\\.|form\\.))"
message: "Potential template injection vulnerability. Sanitize user input before using in templates."
# Pattern 14: Insecure WebSocket Implementation
- pattern: "new\\s+WebSocket\\([^)]*?\\)|io\\.on\\(['\"]connection['\"]"
negative_pattern: "(?:authenticate|authorize|verifyClient|beforeConnect)"
message: "Potentially insecure WebSocket implementation. Implement proper authentication and authorization for WebSocket connections."
# Pattern 15: Insecure Cross-Origin Resource Sharing (CORS)
- pattern: "(?:cors\\(\\{[^}]*?origin\\s*:\\s*['\"]\\*['\"]|app\\.use\\(cors\\(\\{[^}]*?origin\\s*:\\s*['\"]\\*['\"])"
message: "Insecure CORS configuration. Avoid using wildcard (*) for CORS origin in production environments."
- type: suggest
message: |
**JavaScript Secure Design Best Practices:**
1. **Defense in Depth Strategy:**
- Implement multiple layers of security controls
- Don't rely on a single security mechanism
- Example:
```javascript
// Multiple layers of protection
app.use(helmet()); // HTTP security headers
app.use(rateLimit()); // Rate limiting
app.use(cors({ origin: allowedOrigins })); // Restricted CORS
app.use(express.json({ limit: '10kb' })); // Request size limiting
app.use(sanitize()); // Input sanitization
```
2. **Proper Access Control:**
- Implement role-based access control (RBAC)
- Use middleware for authorization checks
- Example:
```javascript
// Role-based middleware
const requireRole = (role) => {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({ error: 'Unauthorized' });
}
if (req.user.role !== role) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
};
// Apply to routes
router.get('/admin/users',
authenticate,
requireRole('admin'),
adminController.listUsers
);
```
3. **Rate Limiting:**
- Implement rate limiting for all API endpoints
- Use different limits for different endpoints based on sensitivity
- Example:
```javascript
const rateLimit = require('express-rate-limit');
// General API rate limit
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
standardHeaders: true,
legacyHeaders: false,
});
// More strict limit for authentication endpoints
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // limit each IP to 5 login attempts per windowMs
standardHeaders: true,
legacyHeaders: false,
});
// Apply rate limiters
app.use('/api/', apiLimiter);
app.use('/api/auth/', authLimiter);
```
4. **Input Validation:**
- Validate all user inputs using schema validation
- Implement both client and server-side validation
- Example:
```javascript
const Joi = require('joi');
// Define validation schema
const userSchema = Joi.object({
username: Joi.string().alphanum().min(3).max(30).required(),
email: Joi.string().email().required(),
password: Joi.string().pattern(new RegExp('^[a-zA-Z0-9]{8,30}$')).required(),
role: Joi.string().valid('user', 'admin').default('user')
});
// Validation middleware
const validateUser = (req, res, next) => {
const { error } = userSchema.validate(req.body);
if (error) {
return res.status(400).json({ error: error.details[0].message });
}
next();
};
// Apply validation
router.post('/users', validateUser, userController.create);
```
5. **Proper Error Handling:**
- Implement centralized error handling
- Avoid exposing sensitive information in error messages
- Example:
```javascript
// Centralized error handler
app.use((err, req, res, next) => {
// Log error for internal use
console.error(err.stack);
// Send appropriate response to client
const statusCode = err.statusCode || 500;
res.status(statusCode).json({
status: 'error',
message: statusCode === 500 ? 'Internal server error' : err.message
});
});
// Custom error class
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
// Usage in controllers
if (!user) {
return next(new AppError('User not found', 404));
}
```
6. **Secure Authentication Design:**
- Use secure password hashing (bcrypt, Argon2)
- Implement proper session management
- Use secure token validation
- Example:
```javascript
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
// Password hashing
const hashPassword = async (password) => {
const salt = await bcrypt.genSalt(12);
return bcrypt.hash(password, salt);
};
// Password verification
const verifyPassword = async (password, hashedPassword) => {
return await bcrypt.compare(password, hashedPassword);
};
// Token generation
const generateToken = (userId) => {
return jwt.sign(
{ id: userId },
process.env.JWT_SECRET,
{ expiresIn: '1h' }
);
};
// Token verification middleware
const verifyToken = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.userId = decoded.id;
next();
} catch (error) {
return res.status(401).json({ error: 'Invalid token' });
}
};
```
7. **Comprehensive Logging:**
- Log security-relevant events
- Include necessary context but avoid sensitive data
- Use structured logging
- Example:
```javascript
const winston = require('winston');
// Create logger
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
defaultMeta: { service: 'user-service' },
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
// Logging middleware
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
logger.info({
method: req.method,
path: req.path,
statusCode: res.statusCode,
duration,
ip: req.ip,
userId: req.user?.id || 'anonymous'
});
});
next();
});
// Security event logging
logger.warn({
event: 'failed_login',
username: req.body.username,
ip: req.ip,
timestamp: new Date().toISOString()
});
```
8. **Secure Configuration Management:**
- Use environment-specific configurations
- Validate configuration at startup
- Example:
```javascript
const Joi = require('joi');
// Define environment variables schema
const envSchema = Joi.object({
NODE_ENV: Joi.string().valid('development', 'production', 'test').required(),
PORT: Joi.number().default(3000),
DATABASE_URL: Joi.string().required(),
JWT_SECRET: Joi.string().min(32).required(),
JWT_EXPIRES_IN: Joi.string().default('1h'),
CORS_ORIGIN: Joi.string().required()
}).unknown();
// Validate environment variables
const { error, value } = envSchema.validate(process.env);
if (error) {
throw new Error(`Configuration validation error: ${error.message}`);
}
// Use validated config
const config = {
env: value.NODE_ENV,
port: value.PORT,
db: {
url: value.DATABASE_URL
},
jwt: {
secret: value.JWT_SECRET,
expiresIn: value.JWT_EXPIRES_IN
},
cors: {
origin: value.CORS_ORIGIN.split(',')
}
};
module.exports = config;
```
9. **Secure File Operations:**
- Validate and sanitize file paths
- Use content-type validation for uploads
- Implement file size limits
- Example:
```javascript
const path = require('path');
const fs = require('fs');
// Secure file access function
const getSecureFilePath = (userInput) => {
// Define allowed directory
const baseDir = path.resolve(__dirname, '../public/files');
// Normalize and resolve full path
const normalizedPath = path.normalize(userInput);
const fullPath = path.join(baseDir, normalizedPath);
// Ensure path is within allowed directory
if (!fullPath.startsWith(baseDir)) {
throw new Error('Invalid file path');
}
return fullPath;
};
// Usage
try {
const filePath = getSecureFilePath(req.params.filename);
const fileContent = fs.readFileSync(filePath, 'utf8');
res.send(fileContent);
} catch (error) {
next(error);
}
```
10. **Secure WebSocket Implementation:**
- Implement authentication for WebSocket connections
- Validate and sanitize WebSocket messages
- Example:
```javascript
const http = require('http');
const socketIo = require('socket.io');
const jwt = require('jsonwebtoken');
const server = http.createServer(app);
const io = socketIo(server);
// WebSocket authentication middleware
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!token) {
return next(new Error('Authentication error'));
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
socket.userId = decoded.id;
next();
} catch (error) {
return next(new Error('Authentication error'));
}
});
io.on('connection', (socket) => {
console.log(`User ${socket.userId} connected`);
// Join user to their own room for private messages
socket.join(`user:${socket.userId}`);
// Message validation
socket.on('message', (data) => {
// Validate message data
if (!data || !data.content || typeof data.content !== 'string') {
return socket.emit('error', { message: 'Invalid message format' });
}
// Process message
// ...
});
});
```
- type: validate
conditions:
# Check 1: Rate limiting implementation
- pattern: "(?:rateLimit|rateLimiter|limiter|throttle)\\([^)]*?\\)"
message: "Implementing rate limiting for API protection."
# Check 2: Input validation
- pattern: "(?:validate|sanitize|check|schema|joi|yup|zod|validator|isValid)"
message: "Using input validation or schema validation."
# Check 3: Proper error handling
- pattern: "(?:try\\s*\\{[^}]*?\\}\\s*catch\\s*\\([^)]*?\\)\\s*\\{[^}]*?(?:res\\.status|next\\(err|next\\(error|errorHandler))"
message: "Implementing proper error handling."
# Check 4: Authentication middleware
- pattern: "(?:authenticate|authorize|requireAuth|isAuthenticated|checkAuth|verifyToken|passport\\.authenticate)"
message: "Using authentication middleware for routes."
# Check 5: Secure configuration
- pattern: "(?:helmet|cors\\(\\{[^}]*?origin\\s*:\\s*(?!['\"]*\\*)['\"])"
message: "Using secure HTTP headers and CORS configuration."
metadata:
priority: high
version: 1.0
tags:
- security
- javascript
- nodejs
- browser
- design
- owasp
- language:javascript
- framework:express
- framework:react
- framework:vue
- framework:angular
- category:security
- subcategory:insecure-design
- standard:owasp-top10
- risk:a04-insecure-design
references:
- "https://owasp.org/Top10/A04_2021-Insecure_Design/"
- "https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html"
- "https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html"
- "https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html"
- "https://cheatsheetseries.owasp.org/cheatsheets/Access_Control_Cheat_Sheet.html"
- "https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html"
- "https://github.com/OWASP/NodeGoat"
</rule>