📦 deps(thirdparty): update snapshots
This commit is contained in:
+298
@@ -0,0 +1,298 @@
|
||||
# Vulnerability Patterns Reference
|
||||
|
||||
Secure vs vulnerable code patterns organized by category. Each pattern shows the vulnerability and its remediation.
|
||||
|
||||
---
|
||||
|
||||
## Input Validation
|
||||
|
||||
### SQL Injection
|
||||
|
||||
```typescript
|
||||
// VULNERABLE
|
||||
const query = `SELECT * FROM users WHERE email = '${userEmail}'`;
|
||||
|
||||
// SECURE - parameterized queries
|
||||
const query = 'SELECT * FROM users WHERE email = ?';
|
||||
db.execute(query, [userEmail]);
|
||||
```
|
||||
|
||||
### XSS (Cross-Site Scripting)
|
||||
|
||||
```typescript
|
||||
// VULNERABLE - direct HTML insertion
|
||||
element.innerHTML = userInput;
|
||||
|
||||
// SECURE - use textContent or sanitize
|
||||
element.textContent = userInput;
|
||||
// OR for rich content
|
||||
element.innerHTML = DOMPurify.sanitize(userInput);
|
||||
```
|
||||
|
||||
### Command Injection
|
||||
|
||||
```typescript
|
||||
// VULNERABLE
|
||||
exec(`convert ${userFilename} output.png`);
|
||||
|
||||
// SECURE - parameterized or allowlist
|
||||
execFile('convert', [userFilename, 'output.png']);
|
||||
```
|
||||
|
||||
### Path Traversal
|
||||
|
||||
```typescript
|
||||
// VULNERABLE
|
||||
const filePath = `/uploads/${userFileName}`;
|
||||
|
||||
// SECURE - validate and normalize
|
||||
const safeName = path.basename(userFileName);
|
||||
const filePath = path.join('/uploads', safeName);
|
||||
if (!filePath.startsWith('/uploads/')) {
|
||||
throw new Error('Invalid path');
|
||||
}
|
||||
```
|
||||
|
||||
### XXE (XML External Entity)
|
||||
|
||||
```typescript
|
||||
// VULNERABLE
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(xmlInput, 'text/xml');
|
||||
|
||||
// SECURE - disable external entities
|
||||
const parser = new DOMParser({
|
||||
locator: {},
|
||||
errorHandler: {},
|
||||
entityResolver: () => null, // Disable DTD processing
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Authentication & Sessions
|
||||
|
||||
### Password Storage
|
||||
|
||||
```typescript
|
||||
// VULNERABLE - plain text or weak hash
|
||||
const hash = md5(password);
|
||||
|
||||
// SECURE - bcrypt/argon2 with salt
|
||||
const hash = await bcrypt.hash(password, 12);
|
||||
```
|
||||
|
||||
### Session Management
|
||||
|
||||
```typescript
|
||||
// VULNERABLE - predictable session IDs
|
||||
const sessionId = userId + Date.now();
|
||||
|
||||
// SECURE - cryptographically random
|
||||
const sessionId = crypto.randomBytes(32).toString('hex');
|
||||
|
||||
// Security attributes
|
||||
res.cookie('session', sessionId, {
|
||||
httpOnly: true,
|
||||
secure: true, // HTTPS only
|
||||
sameSite: 'strict',
|
||||
maxAge: 3600000, // 1 hour
|
||||
});
|
||||
```
|
||||
|
||||
### JWT Handling
|
||||
|
||||
```typescript
|
||||
// VULNERABLE - no signature verification
|
||||
const payload = JSON.parse(atob(token.split('.')[1]));
|
||||
|
||||
// SECURE - verify signature
|
||||
const payload = jwt.verify(token, SECRET_KEY, {
|
||||
algorithms: ['HS256'], // Specify allowed algorithms
|
||||
issuer: 'your-app',
|
||||
audience: 'your-api',
|
||||
});
|
||||
```
|
||||
|
||||
### Password Reset
|
||||
|
||||
```typescript
|
||||
// VULNERABLE - predictable tokens
|
||||
const resetToken = userId + '-' + Date.now();
|
||||
|
||||
// SECURE - cryptographically random with expiry
|
||||
const resetToken = crypto.randomBytes(32).toString('hex');
|
||||
await db.execute(
|
||||
'INSERT INTO reset_tokens (user_id, token, expires_at) VALUES (?, ?, ?)',
|
||||
[userId, await bcrypt.hash(resetToken, 10), Date.now() + 3600000]
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Authorization
|
||||
|
||||
### Broken Access Control
|
||||
|
||||
```typescript
|
||||
// VULNERABLE - client-side only check
|
||||
if (user.isAdmin) {
|
||||
// show admin panel
|
||||
}
|
||||
|
||||
// SECURE - server-side enforcement
|
||||
app.get('/admin/users', requireAdmin, (req, res) => {
|
||||
if (!req.user?.isAdmin) {
|
||||
return res.status(403).json({ error: 'Forbidden' });
|
||||
}
|
||||
// Admin operation
|
||||
});
|
||||
```
|
||||
|
||||
### IDOR (Insecure Direct Object Reference)
|
||||
|
||||
```typescript
|
||||
// VULNERABLE - no ownership check
|
||||
app.get('/api/documents/:id', async (req, res) => {
|
||||
const doc = await db.getDocument(req.params.id);
|
||||
res.json(doc);
|
||||
});
|
||||
|
||||
// SECURE - verify ownership
|
||||
app.get('/api/documents/:id', async (req, res) => {
|
||||
const doc = await db.getDocument(req.params.id);
|
||||
if (doc.userId !== req.user.id && !req.user.isAdmin) {
|
||||
return res.status(403).json({ error: 'Forbidden' });
|
||||
}
|
||||
res.json(doc);
|
||||
});
|
||||
```
|
||||
|
||||
### Privilege Escalation
|
||||
|
||||
```typescript
|
||||
// VULNERABLE - role from client input
|
||||
app.post('/api/users', async (req, res) => {
|
||||
const user = await createUser({
|
||||
...req.body, // Includes role: 'admin' from malicious client
|
||||
});
|
||||
});
|
||||
|
||||
// SECURE - explicit allowlist
|
||||
app.post('/api/users', async (req, res) => {
|
||||
const allowedFields = ['name', 'email', 'password'];
|
||||
const userData = pick(req.body, allowedFields);
|
||||
const user = await createUser({
|
||||
...userData,
|
||||
role: 'user', // Server controls role
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cryptography
|
||||
|
||||
### Weak Algorithms
|
||||
|
||||
```typescript
|
||||
// VULNERABLE - deprecated algorithms
|
||||
const hash = crypto.createHash('md5').update(data).digest('hex');
|
||||
const cipher = crypto.createCipher('des', key);
|
||||
|
||||
// SECURE - modern algorithms
|
||||
const hash = crypto.createHash('sha256').update(data).digest('hex');
|
||||
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
|
||||
```
|
||||
|
||||
### Hardcoded Secrets
|
||||
|
||||
```typescript
|
||||
// VULNERABLE
|
||||
const API_KEY = 'sk-1234567890abcdef';
|
||||
const DB_PASSWORD = 'admin123';
|
||||
|
||||
// SECURE - environment variables
|
||||
const API_KEY = process.env.API_KEY;
|
||||
const DB_PASSWORD = process.env.DB_PASSWORD;
|
||||
|
||||
if (!API_KEY || !DB_PASSWORD) {
|
||||
throw new Error('Missing required environment variables');
|
||||
}
|
||||
```
|
||||
|
||||
### Insufficient Randomness
|
||||
|
||||
```typescript
|
||||
// VULNERABLE - predictable
|
||||
const token = Math.random().toString(36);
|
||||
|
||||
// SECURE - cryptographically secure
|
||||
const token = crypto.randomBytes(32).toString('hex');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Exposure
|
||||
|
||||
### Sensitive Data in Logs
|
||||
|
||||
```typescript
|
||||
// VULNERABLE
|
||||
logger.info('User login', { email, password, ssn });
|
||||
|
||||
// SECURE - redact sensitive fields
|
||||
logger.info('User login', {
|
||||
email,
|
||||
password: '[REDACTED]',
|
||||
ssn: '[REDACTED]',
|
||||
});
|
||||
```
|
||||
|
||||
### Error Message Disclosure
|
||||
|
||||
```typescript
|
||||
// VULNERABLE - exposes internals
|
||||
catch (err) {
|
||||
res.status(500).json({ error: err.stack });
|
||||
}
|
||||
|
||||
// SECURE - generic message
|
||||
catch (err) {
|
||||
logger.error('Internal error', err);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
```
|
||||
|
||||
### Timing Attacks
|
||||
|
||||
```typescript
|
||||
// VULNERABLE - early exit leaks info
|
||||
if (user.password !== inputPassword) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// SECURE - constant-time comparison
|
||||
return crypto.timingSafeEqual(
|
||||
Buffer.from(user.password),
|
||||
Buffer.from(inputPassword)
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Category | Vulnerable Pattern | Secure Pattern |
|
||||
|----------|-------------------|----------------|
|
||||
| SQL Injection | String concatenation | Parameterized queries |
|
||||
| XSS | innerHTML with user input | textContent or DOMPurify |
|
||||
| Command Injection | exec() with user input | execFile() with array args |
|
||||
| Path Traversal | Direct path concat | path.basename + prefix check |
|
||||
| Password Storage | MD5/SHA1/plain | bcrypt (cost 12+) or argon2 |
|
||||
| Session IDs | Predictable (Date.now) | crypto.randomBytes(32) |
|
||||
| JWT | Skip verification | jwt.verify() with algorithm |
|
||||
| Access Control | Client-side only | Server-side on every request |
|
||||
| IDOR | No ownership check | Verify user owns resource |
|
||||
| Secrets | Hardcoded in code | Environment variables |
|
||||
| Error Messages | Stack traces to users | Generic error + log details |
|
||||
Reference in New Issue
Block a user