omgkit 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/plugin/skills/SKILL_STANDARDS.md +743 -0
- package/plugin/skills/databases/mongodb/SKILL.md +797 -28
- package/plugin/skills/databases/postgresql/SKILL.md +494 -18
- package/plugin/skills/databases/prisma/SKILL.md +776 -30
- package/plugin/skills/databases/redis/SKILL.md +885 -25
- package/plugin/skills/devops/aws/SKILL.md +686 -28
- package/plugin/skills/devops/docker/SKILL.md +466 -18
- package/plugin/skills/devops/github-actions/SKILL.md +684 -29
- package/plugin/skills/devops/kubernetes/SKILL.md +621 -24
- package/plugin/skills/frameworks/django/SKILL.md +920 -20
- package/plugin/skills/frameworks/express/SKILL.md +1361 -35
- package/plugin/skills/frameworks/fastapi/SKILL.md +1260 -33
- package/plugin/skills/frameworks/laravel/SKILL.md +1244 -31
- package/plugin/skills/frameworks/nestjs/SKILL.md +1005 -26
- package/plugin/skills/frameworks/nextjs/SKILL.md +407 -44
- package/plugin/skills/frameworks/rails/SKILL.md +594 -28
- package/plugin/skills/frameworks/react/SKILL.md +1006 -32
- package/plugin/skills/frameworks/spring/SKILL.md +528 -35
- package/plugin/skills/frameworks/vue/SKILL.md +1296 -27
- package/plugin/skills/frontend/accessibility/SKILL.md +1108 -34
- package/plugin/skills/frontend/frontend-design/SKILL.md +1304 -26
- package/plugin/skills/frontend/responsive/SKILL.md +847 -21
- package/plugin/skills/frontend/shadcn-ui/SKILL.md +976 -38
- package/plugin/skills/frontend/tailwindcss/SKILL.md +831 -35
- package/plugin/skills/frontend/threejs/SKILL.md +1298 -29
- package/plugin/skills/languages/javascript/SKILL.md +935 -31
- package/plugin/skills/languages/python/SKILL.md +489 -25
- package/plugin/skills/languages/typescript/SKILL.md +379 -30
- package/plugin/skills/methodology/brainstorming/SKILL.md +597 -23
- package/plugin/skills/methodology/defense-in-depth/SKILL.md +832 -34
- package/plugin/skills/methodology/dispatching-parallel-agents/SKILL.md +665 -31
- package/plugin/skills/methodology/executing-plans/SKILL.md +556 -24
- package/plugin/skills/methodology/finishing-development-branch/SKILL.md +595 -25
- package/plugin/skills/methodology/problem-solving/SKILL.md +429 -61
- package/plugin/skills/methodology/receiving-code-review/SKILL.md +536 -24
- package/plugin/skills/methodology/requesting-code-review/SKILL.md +632 -21
- package/plugin/skills/methodology/root-cause-tracing/SKILL.md +641 -30
- package/plugin/skills/methodology/sequential-thinking/SKILL.md +262 -3
- package/plugin/skills/methodology/systematic-debugging/SKILL.md +571 -32
- package/plugin/skills/methodology/test-driven-development/SKILL.md +779 -24
- package/plugin/skills/methodology/testing-anti-patterns/SKILL.md +691 -29
- package/plugin/skills/methodology/token-optimization/SKILL.md +598 -29
- package/plugin/skills/methodology/verification-before-completion/SKILL.md +543 -22
- package/plugin/skills/methodology/writing-plans/SKILL.md +590 -18
- package/plugin/skills/omega/omega-architecture/SKILL.md +838 -39
- package/plugin/skills/omega/omega-coding/SKILL.md +636 -39
- package/plugin/skills/omega/omega-sprint/SKILL.md +855 -48
- package/plugin/skills/omega/omega-testing/SKILL.md +940 -41
- package/plugin/skills/omega/omega-thinking/SKILL.md +703 -50
- package/plugin/skills/security/better-auth/SKILL.md +1065 -28
- package/plugin/skills/security/oauth/SKILL.md +968 -31
- package/plugin/skills/security/owasp/SKILL.md +894 -33
- package/plugin/skills/testing/playwright/SKILL.md +764 -38
- package/plugin/skills/testing/pytest/SKILL.md +873 -36
- package/plugin/skills/testing/vitest/SKILL.md +980 -35
|
@@ -1,51 +1,849 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: defense-in-depth
|
|
3
|
-
description:
|
|
3
|
+
description: Layered security architecture with multiple protective barriers for comprehensive system protection
|
|
4
|
+
category: methodology
|
|
5
|
+
triggers:
|
|
6
|
+
- defense in depth
|
|
7
|
+
- security layers
|
|
8
|
+
- layered security
|
|
9
|
+
- security architecture
|
|
10
|
+
- multiple barriers
|
|
11
|
+
- security controls
|
|
12
|
+
- protective layers
|
|
4
13
|
---
|
|
5
14
|
|
|
6
|
-
# Defense in Depth
|
|
15
|
+
# Defense in Depth
|
|
7
16
|
|
|
8
|
-
|
|
17
|
+
Implement **layered security architecture** with multiple protective barriers. This skill provides frameworks for building systems where each layer provides independent protection, ensuring no single point of failure compromises security.
|
|
9
18
|
|
|
10
|
-
|
|
11
|
-
- Firewall
|
|
12
|
-
- Rate limiting
|
|
13
|
-
- WAF
|
|
19
|
+
## Purpose
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
- VPC
|
|
17
|
-
- Security groups
|
|
18
|
-
- TLS everywhere
|
|
21
|
+
Build resilient security through layered protection:
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
23
|
+
- Design multiple independent security barriers
|
|
24
|
+
- Ensure each layer catches what others miss
|
|
25
|
+
- Prevent single points of security failure
|
|
26
|
+
- Slow down attackers at every step
|
|
27
|
+
- Provide time to detect and respond to breaches
|
|
28
|
+
- Limit blast radius when breaches occur
|
|
29
|
+
- Maintain security even when some controls fail
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
- Encryption at rest
|
|
27
|
-
- Encryption in transit
|
|
28
|
-
- Access control
|
|
31
|
+
## Features
|
|
29
32
|
|
|
30
|
-
###
|
|
31
|
-
- Logging
|
|
32
|
-
- Alerting
|
|
33
|
-
- Audit trails
|
|
33
|
+
### 1. The Defense in Depth Model
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
```markdown
|
|
36
|
+
## Security Layers Architecture
|
|
37
|
+
|
|
38
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
39
|
+
│ DEFENSE IN DEPTH MODEL │
|
|
40
|
+
├─────────────────────────────────────────────────────────────────────────┤
|
|
41
|
+
│ │
|
|
42
|
+
│ ┌───────────────────────────────────────────────────────────────────┐ │
|
|
43
|
+
│ │ LAYER 1: PERIMETER │ │
|
|
44
|
+
│ │ ════════════════════ │ │
|
|
45
|
+
│ │ WAF │ DDoS Protection │ Rate Limiting │ IP Filtering │ │
|
|
46
|
+
│ │ │ │
|
|
47
|
+
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
|
|
48
|
+
│ │ │ LAYER 2: NETWORK │ │ │
|
|
49
|
+
│ │ │ ═════════════════ │ │ │
|
|
50
|
+
│ │ │ VPC │ Security Groups │ Network Policies │ TLS Everywhere │ │ │
|
|
51
|
+
│ │ │ │ │ │
|
|
52
|
+
│ │ │ ┌───────────────────────────────────────────────────────┐ │ │ │
|
|
53
|
+
│ │ │ │ LAYER 3: APPLICATION │ │ │ │
|
|
54
|
+
│ │ │ │ ═════════════════════ │ │ │ │
|
|
55
|
+
│ │ │ │ Input Validation │ Output Encoding │ CSRF │ CSP │ │ │ │
|
|
56
|
+
│ │ │ │ │ │ │ │
|
|
57
|
+
│ │ │ │ ┌─────────────────────────────────────────────────┐ │ │ │ │
|
|
58
|
+
│ │ │ │ │ LAYER 4: DATA │ │ │ │ │
|
|
59
|
+
│ │ │ │ │ ═══════════════ │ │ │ │ │
|
|
60
|
+
│ │ │ │ │ Encryption at Rest │ Encryption in Transit │ │ │ │ │
|
|
61
|
+
│ │ │ │ │ Access Control │ Data Classification │ │ │ │ │
|
|
62
|
+
│ │ │ │ │ │ │ │ │ │
|
|
63
|
+
│ │ │ │ │ ┌───────────────────────────────────────────┐ │ │ │ │ │
|
|
64
|
+
│ │ │ │ │ │ LAYER 5: IDENTITY │ │ │ │ │ │
|
|
65
|
+
│ │ │ │ │ │ ═══════════════════ │ │ │ │ │ │
|
|
66
|
+
│ │ │ │ │ │ MFA │ Least Privilege │ Session Mgmt │ │ │ │ │ │
|
|
67
|
+
│ │ │ │ │ └───────────────────────────────────────────┘ │ │ │ │ │
|
|
68
|
+
│ │ │ │ └─────────────────────────────────────────────────┘ │ │ │ │
|
|
69
|
+
│ │ │ └───────────────────────────────────────────────────────┘ │ │ │
|
|
70
|
+
│ │ └─────────────────────────────────────────────────────────────┘ │ │
|
|
71
|
+
│ └───────────────────────────────────────────────────────────────────┘ │
|
|
72
|
+
│ │
|
|
73
|
+
│ ┌───────────────────────────────────────────────────────────────────┐ │
|
|
74
|
+
│ │ CROSS-CUTTING: MONITORING & DETECTION │ │
|
|
75
|
+
│ │ Logging │ Alerting │ Anomaly Detection │ Incident Response │ │
|
|
76
|
+
│ └───────────────────────────────────────────────────────────────────┘ │
|
|
77
|
+
│ │
|
|
78
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
79
|
+
|
|
80
|
+
PRINCIPLE: If one layer fails, others still protect the asset.
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 2. Layer 1: Perimeter Security
|
|
37
84
|
|
|
38
|
-
## Implementation
|
|
39
85
|
```typescript
|
|
40
|
-
|
|
41
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Perimeter Security: First line of defense
|
|
88
|
+
* Block attacks before they reach your application
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
// WAF (Web Application Firewall) Configuration
|
|
92
|
+
const wafConfig = {
|
|
93
|
+
rules: [
|
|
94
|
+
// SQL Injection patterns
|
|
95
|
+
{
|
|
96
|
+
name: 'sql-injection',
|
|
97
|
+
action: 'block',
|
|
98
|
+
patterns: [
|
|
99
|
+
/(\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|ALTER)\b)/i,
|
|
100
|
+
/(\b(OR|AND)\s+\d+\s*=\s*\d+)/i,
|
|
101
|
+
/(--|\#|\/\*)/
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
// XSS patterns
|
|
105
|
+
{
|
|
106
|
+
name: 'xss-attack',
|
|
107
|
+
action: 'block',
|
|
108
|
+
patterns: [
|
|
109
|
+
/<script\b[^>]*>/i,
|
|
110
|
+
/javascript:/i,
|
|
111
|
+
/on\w+\s*=/i
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
// Path traversal
|
|
115
|
+
{
|
|
116
|
+
name: 'path-traversal',
|
|
117
|
+
action: 'block',
|
|
118
|
+
patterns: [
|
|
119
|
+
/\.\.\//,
|
|
120
|
+
/\.\.\\/
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Rate Limiting Configuration
|
|
127
|
+
interface RateLimitConfig {
|
|
128
|
+
global: {
|
|
129
|
+
requestsPerSecond: number;
|
|
130
|
+
burstSize: number;
|
|
131
|
+
};
|
|
132
|
+
perEndpoint: Map<string, EndpointLimit>;
|
|
133
|
+
perUser: {
|
|
134
|
+
requestsPerMinute: number;
|
|
135
|
+
requestsPerHour: number;
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const rateLimiting: RateLimitConfig = {
|
|
140
|
+
global: {
|
|
141
|
+
requestsPerSecond: 10000,
|
|
142
|
+
burstSize: 15000
|
|
143
|
+
},
|
|
144
|
+
perEndpoint: new Map([
|
|
145
|
+
['/api/login', { requestsPerMinute: 5, lockoutDuration: 900 }],
|
|
146
|
+
['/api/register', { requestsPerMinute: 2, lockoutDuration: 3600 }],
|
|
147
|
+
['/api/password-reset', { requestsPerMinute: 3, lockoutDuration: 3600 }]
|
|
148
|
+
]),
|
|
149
|
+
perUser: {
|
|
150
|
+
requestsPerMinute: 60,
|
|
151
|
+
requestsPerHour: 1000
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// DDoS Protection
|
|
156
|
+
class DDoSProtection {
|
|
157
|
+
private connectionTracker: Map<string, ConnectionInfo> = new Map();
|
|
42
158
|
|
|
43
|
-
|
|
44
|
-
const
|
|
159
|
+
async handleRequest(request: Request): Promise<Response | null> {
|
|
160
|
+
const clientIp = request.headers.get('cf-connecting-ip')!;
|
|
45
161
|
|
|
46
|
-
//
|
|
47
|
-
|
|
162
|
+
// Check if IP is in blocklist
|
|
163
|
+
if (await this.isBlocked(clientIp)) {
|
|
164
|
+
return new Response('Blocked', { status: 403 });
|
|
165
|
+
}
|
|
48
166
|
|
|
49
|
-
//
|
|
50
|
-
|
|
167
|
+
// Track connection patterns
|
|
168
|
+
const info = this.trackConnection(clientIp);
|
|
169
|
+
|
|
170
|
+
// Detect anomalies
|
|
171
|
+
if (this.isAnomalous(info)) {
|
|
172
|
+
await this.triggerProtection(clientIp);
|
|
173
|
+
return new Response('Rate Limited', { status: 429 });
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return null; // Allow through
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
private isAnomalous(info: ConnectionInfo): boolean {
|
|
180
|
+
return (
|
|
181
|
+
info.requestsPerSecond > 100 ||
|
|
182
|
+
info.uniquePathsPerMinute > 500 ||
|
|
183
|
+
info.payloadSize > 10_000_000
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
51
187
|
```
|
|
188
|
+
|
|
189
|
+
### 3. Layer 2: Network Security
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
/**
|
|
193
|
+
* Network Security: Isolate and protect internal communication
|
|
194
|
+
*/
|
|
195
|
+
|
|
196
|
+
// VPC and Security Group Configuration (AWS example)
|
|
197
|
+
const networkConfig = {
|
|
198
|
+
vpc: {
|
|
199
|
+
cidr: '10.0.0.0/16',
|
|
200
|
+
subnets: {
|
|
201
|
+
public: ['10.0.1.0/24', '10.0.2.0/24'], // Load balancers
|
|
202
|
+
private: ['10.0.10.0/24', '10.0.11.0/24'], // Application
|
|
203
|
+
data: ['10.0.20.0/24', '10.0.21.0/24'] // Databases
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
securityGroups: {
|
|
208
|
+
loadBalancer: {
|
|
209
|
+
inbound: [
|
|
210
|
+
{ port: 443, source: '0.0.0.0/0' },
|
|
211
|
+
{ port: 80, source: '0.0.0.0/0' } // Redirect to HTTPS
|
|
212
|
+
],
|
|
213
|
+
outbound: [
|
|
214
|
+
{ port: 8080, destination: 'application-sg' }
|
|
215
|
+
]
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
application: {
|
|
219
|
+
inbound: [
|
|
220
|
+
{ port: 8080, source: 'load-balancer-sg' }
|
|
221
|
+
],
|
|
222
|
+
outbound: [
|
|
223
|
+
{ port: 5432, destination: 'database-sg' },
|
|
224
|
+
{ port: 6379, destination: 'cache-sg' },
|
|
225
|
+
{ port: 443, destination: '0.0.0.0/0' } // External APIs
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
database: {
|
|
230
|
+
inbound: [
|
|
231
|
+
{ port: 5432, source: 'application-sg' }
|
|
232
|
+
],
|
|
233
|
+
outbound: [] // No outbound access
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// Mutual TLS (mTLS) for Service-to-Service
|
|
239
|
+
class MTLSClient {
|
|
240
|
+
private certificate: Certificate;
|
|
241
|
+
private privateKey: PrivateKey;
|
|
242
|
+
private caCertificate: Certificate;
|
|
243
|
+
|
|
244
|
+
async makeRequest(url: string, options: RequestInit): Promise<Response> {
|
|
245
|
+
const agent = new https.Agent({
|
|
246
|
+
cert: this.certificate,
|
|
247
|
+
key: this.privateKey,
|
|
248
|
+
ca: this.caCertificate,
|
|
249
|
+
rejectUnauthorized: true
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
return fetch(url, {
|
|
253
|
+
...options,
|
|
254
|
+
// @ts-ignore
|
|
255
|
+
agent
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Network Policy (Kubernetes)
|
|
261
|
+
const networkPolicy = {
|
|
262
|
+
apiVersion: 'networking.k8s.io/v1',
|
|
263
|
+
kind: 'NetworkPolicy',
|
|
264
|
+
metadata: {
|
|
265
|
+
name: 'api-server-policy',
|
|
266
|
+
namespace: 'production'
|
|
267
|
+
},
|
|
268
|
+
spec: {
|
|
269
|
+
podSelector: {
|
|
270
|
+
matchLabels: { app: 'api-server' }
|
|
271
|
+
},
|
|
272
|
+
policyTypes: ['Ingress', 'Egress'],
|
|
273
|
+
ingress: [
|
|
274
|
+
{
|
|
275
|
+
from: [
|
|
276
|
+
{ podSelector: { matchLabels: { app: 'ingress-controller' } } }
|
|
277
|
+
],
|
|
278
|
+
ports: [{ port: 8080, protocol: 'TCP' }]
|
|
279
|
+
}
|
|
280
|
+
],
|
|
281
|
+
egress: [
|
|
282
|
+
{
|
|
283
|
+
to: [
|
|
284
|
+
{ podSelector: { matchLabels: { app: 'database' } } }
|
|
285
|
+
],
|
|
286
|
+
ports: [{ port: 5432, protocol: 'TCP' }]
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
to: [
|
|
290
|
+
{ namespaceSelector: { matchLabels: { name: 'kube-system' } } }
|
|
291
|
+
],
|
|
292
|
+
ports: [{ port: 53, protocol: 'UDP' }] // DNS
|
|
293
|
+
}
|
|
294
|
+
]
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### 4. Layer 3: Application Security
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
/**
|
|
303
|
+
* Application Security: Secure code and request handling
|
|
304
|
+
*/
|
|
305
|
+
|
|
306
|
+
import { z } from 'zod';
|
|
307
|
+
import DOMPurify from 'dompurify';
|
|
308
|
+
import csrf from 'csrf';
|
|
309
|
+
|
|
310
|
+
// Input Validation - Never trust user input
|
|
311
|
+
const userInputSchema = z.object({
|
|
312
|
+
email: z.string().email().max(254),
|
|
313
|
+
name: z.string().min(1).max(100).regex(/^[\p{L}\s'-]+$/u),
|
|
314
|
+
age: z.number().int().min(0).max(150).optional(),
|
|
315
|
+
bio: z.string().max(1000).optional()
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
function validateInput<T>(schema: z.ZodSchema<T>, data: unknown): T {
|
|
319
|
+
try {
|
|
320
|
+
return schema.parse(data);
|
|
321
|
+
} catch (error) {
|
|
322
|
+
if (error instanceof z.ZodError) {
|
|
323
|
+
throw new ValidationError(error.errors);
|
|
324
|
+
}
|
|
325
|
+
throw error;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Output Encoding - Prevent XSS
|
|
330
|
+
function sanitizeForHTML(input: string): string {
|
|
331
|
+
return DOMPurify.sanitize(input, {
|
|
332
|
+
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br'],
|
|
333
|
+
ALLOWED_ATTR: ['href', 'title'],
|
|
334
|
+
ALLOW_DATA_ATTR: false
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function escapeForSQL(input: string): string {
|
|
339
|
+
// Always use parameterized queries instead!
|
|
340
|
+
throw new Error('Use parameterized queries, not escaping');
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// CSRF Protection
|
|
344
|
+
class CSRFProtection {
|
|
345
|
+
private tokens = new csrf();
|
|
346
|
+
|
|
347
|
+
generateToken(sessionId: string): string {
|
|
348
|
+
const secret = this.getSecretForSession(sessionId);
|
|
349
|
+
return this.tokens.create(secret);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
verifyToken(sessionId: string, token: string): boolean {
|
|
353
|
+
const secret = this.getSecretForSession(sessionId);
|
|
354
|
+
return this.tokens.verify(secret, token);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Content Security Policy
|
|
359
|
+
const contentSecurityPolicy = {
|
|
360
|
+
'default-src': ["'self'"],
|
|
361
|
+
'script-src': ["'self'", "'strict-dynamic'"],
|
|
362
|
+
'style-src': ["'self'", "'unsafe-inline'"], // Consider using nonces
|
|
363
|
+
'img-src': ["'self'", 'data:', 'https:'],
|
|
364
|
+
'font-src': ["'self'"],
|
|
365
|
+
'connect-src': ["'self'", 'https://api.example.com'],
|
|
366
|
+
'frame-ancestors': ["'none'"],
|
|
367
|
+
'base-uri': ["'self'"],
|
|
368
|
+
'form-action': ["'self'"]
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
// Security Headers Middleware
|
|
372
|
+
function securityHeaders(req: Request, res: Response, next: NextFunction) {
|
|
373
|
+
// Prevent clickjacking
|
|
374
|
+
res.setHeader('X-Frame-Options', 'DENY');
|
|
375
|
+
|
|
376
|
+
// Prevent MIME sniffing
|
|
377
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
378
|
+
|
|
379
|
+
// Enable XSS filter (legacy browsers)
|
|
380
|
+
res.setHeader('X-XSS-Protection', '1; mode=block');
|
|
381
|
+
|
|
382
|
+
// Force HTTPS
|
|
383
|
+
res.setHeader(
|
|
384
|
+
'Strict-Transport-Security',
|
|
385
|
+
'max-age=31536000; includeSubDomains; preload'
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
// CSP
|
|
389
|
+
const cspValue = Object.entries(contentSecurityPolicy)
|
|
390
|
+
.map(([key, values]) => `${key} ${values.join(' ')}`)
|
|
391
|
+
.join('; ');
|
|
392
|
+
res.setHeader('Content-Security-Policy', cspValue);
|
|
393
|
+
|
|
394
|
+
next();
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### 5. Layer 4: Data Security
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
/**
|
|
402
|
+
* Data Security: Protect data at rest and in transit
|
|
403
|
+
*/
|
|
404
|
+
|
|
405
|
+
import { createCipheriv, createDecipheriv, randomBytes, scrypt } from 'crypto';
|
|
406
|
+
|
|
407
|
+
// Encryption at Rest
|
|
408
|
+
class FieldLevelEncryption {
|
|
409
|
+
private algorithm = 'aes-256-gcm';
|
|
410
|
+
private keyLength = 32;
|
|
411
|
+
private ivLength = 16;
|
|
412
|
+
private tagLength = 16;
|
|
413
|
+
|
|
414
|
+
async encrypt(
|
|
415
|
+
plaintext: string,
|
|
416
|
+
encryptionKey: Buffer
|
|
417
|
+
): Promise<EncryptedData> {
|
|
418
|
+
const iv = randomBytes(this.ivLength);
|
|
419
|
+
const cipher = createCipheriv(this.algorithm, encryptionKey, iv);
|
|
420
|
+
|
|
421
|
+
let encrypted = cipher.update(plaintext, 'utf8', 'base64');
|
|
422
|
+
encrypted += cipher.final('base64');
|
|
423
|
+
|
|
424
|
+
const tag = cipher.getAuthTag();
|
|
425
|
+
|
|
426
|
+
return {
|
|
427
|
+
ciphertext: encrypted,
|
|
428
|
+
iv: iv.toString('base64'),
|
|
429
|
+
tag: tag.toString('base64'),
|
|
430
|
+
algorithm: this.algorithm
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
async decrypt(
|
|
435
|
+
data: EncryptedData,
|
|
436
|
+
encryptionKey: Buffer
|
|
437
|
+
): Promise<string> {
|
|
438
|
+
const decipher = createDecipheriv(
|
|
439
|
+
data.algorithm,
|
|
440
|
+
encryptionKey,
|
|
441
|
+
Buffer.from(data.iv, 'base64')
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
decipher.setAuthTag(Buffer.from(data.tag, 'base64'));
|
|
445
|
+
|
|
446
|
+
let decrypted = decipher.update(data.ciphertext, 'base64', 'utf8');
|
|
447
|
+
decrypted += decipher.final('utf8');
|
|
448
|
+
|
|
449
|
+
return decrypted;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Data Classification and Handling
|
|
454
|
+
type DataClassification = 'public' | 'internal' | 'confidential' | 'restricted';
|
|
455
|
+
|
|
456
|
+
interface DataHandlingPolicy {
|
|
457
|
+
classification: DataClassification;
|
|
458
|
+
encryption: {
|
|
459
|
+
atRest: boolean;
|
|
460
|
+
inTransit: boolean;
|
|
461
|
+
};
|
|
462
|
+
accessControl: {
|
|
463
|
+
roles: string[];
|
|
464
|
+
mfa: boolean;
|
|
465
|
+
};
|
|
466
|
+
retention: {
|
|
467
|
+
maxDays: number;
|
|
468
|
+
archiveAfterDays?: number;
|
|
469
|
+
};
|
|
470
|
+
logging: {
|
|
471
|
+
accessLogging: boolean;
|
|
472
|
+
auditLogging: boolean;
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const dataHandlingPolicies: Record<DataClassification, DataHandlingPolicy> = {
|
|
477
|
+
public: {
|
|
478
|
+
classification: 'public',
|
|
479
|
+
encryption: { atRest: false, inTransit: true },
|
|
480
|
+
accessControl: { roles: ['*'], mfa: false },
|
|
481
|
+
retention: { maxDays: 365 * 10 },
|
|
482
|
+
logging: { accessLogging: false, auditLogging: false }
|
|
483
|
+
},
|
|
484
|
+
internal: {
|
|
485
|
+
classification: 'internal',
|
|
486
|
+
encryption: { atRest: false, inTransit: true },
|
|
487
|
+
accessControl: { roles: ['employee'], mfa: false },
|
|
488
|
+
retention: { maxDays: 365 * 5 },
|
|
489
|
+
logging: { accessLogging: true, auditLogging: false }
|
|
490
|
+
},
|
|
491
|
+
confidential: {
|
|
492
|
+
classification: 'confidential',
|
|
493
|
+
encryption: { atRest: true, inTransit: true },
|
|
494
|
+
accessControl: { roles: ['authorized'], mfa: true },
|
|
495
|
+
retention: { maxDays: 365 * 3, archiveAfterDays: 365 },
|
|
496
|
+
logging: { accessLogging: true, auditLogging: true }
|
|
497
|
+
},
|
|
498
|
+
restricted: {
|
|
499
|
+
classification: 'restricted',
|
|
500
|
+
encryption: { atRest: true, inTransit: true },
|
|
501
|
+
accessControl: { roles: ['privileged'], mfa: true },
|
|
502
|
+
retention: { maxDays: 365, archiveAfterDays: 90 },
|
|
503
|
+
logging: { accessLogging: true, auditLogging: true }
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
// Database Access Control
|
|
508
|
+
class SecureDataAccess {
|
|
509
|
+
async query<T>(
|
|
510
|
+
sql: string,
|
|
511
|
+
params: unknown[],
|
|
512
|
+
context: SecurityContext
|
|
513
|
+
): Promise<T[]> {
|
|
514
|
+
// 1. Always use parameterized queries
|
|
515
|
+
// 2. Apply row-level security
|
|
516
|
+
const securedSql = this.applyRowLevelSecurity(sql, context);
|
|
517
|
+
|
|
518
|
+
// 3. Audit the access
|
|
519
|
+
await this.auditLog({
|
|
520
|
+
action: 'data_access',
|
|
521
|
+
query: sql,
|
|
522
|
+
user: context.userId,
|
|
523
|
+
timestamp: new Date(),
|
|
524
|
+
classification: this.getDataClassification(sql)
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
// 4. Execute with minimal privileges
|
|
528
|
+
return this.executeWithRole(securedSql, params, context.dbRole);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
### 6. Layer 5: Identity Security
|
|
534
|
+
|
|
535
|
+
```typescript
|
|
536
|
+
/**
|
|
537
|
+
* Identity Security: Authentication and Authorization
|
|
538
|
+
*/
|
|
539
|
+
|
|
540
|
+
// Multi-Factor Authentication
|
|
541
|
+
interface MFAConfig {
|
|
542
|
+
required: boolean;
|
|
543
|
+
methods: MFAMethod[];
|
|
544
|
+
sessionDuration: number; // seconds
|
|
545
|
+
reauthenticationTriggers: string[];
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
type MFAMethod = 'totp' | 'webauthn' | 'sms' | 'email';
|
|
549
|
+
|
|
550
|
+
class MFAService {
|
|
551
|
+
async verifyMFA(
|
|
552
|
+
userId: string,
|
|
553
|
+
method: MFAMethod,
|
|
554
|
+
code: string
|
|
555
|
+
): Promise<boolean> {
|
|
556
|
+
switch (method) {
|
|
557
|
+
case 'totp':
|
|
558
|
+
return this.verifyTOTP(userId, code);
|
|
559
|
+
case 'webauthn':
|
|
560
|
+
return this.verifyWebAuthn(userId, code);
|
|
561
|
+
case 'sms':
|
|
562
|
+
case 'email':
|
|
563
|
+
return this.verifyOTP(userId, method, code);
|
|
564
|
+
default:
|
|
565
|
+
throw new Error(`Unsupported MFA method: ${method}`);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
private async verifyTOTP(userId: string, code: string): Promise<boolean> {
|
|
570
|
+
const secret = await this.getTOTPSecret(userId);
|
|
571
|
+
const expected = this.generateTOTP(secret);
|
|
572
|
+
|
|
573
|
+
// Check current and adjacent time windows
|
|
574
|
+
const windows = [-1, 0, 1];
|
|
575
|
+
return windows.some(offset =>
|
|
576
|
+
this.generateTOTP(secret, offset) === code
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// Principle of Least Privilege
|
|
582
|
+
interface Permission {
|
|
583
|
+
resource: string;
|
|
584
|
+
actions: string[];
|
|
585
|
+
conditions?: PermissionCondition[];
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
interface Role {
|
|
589
|
+
name: string;
|
|
590
|
+
permissions: Permission[];
|
|
591
|
+
inherits?: string[];
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const roleDefinitions: Role[] = [
|
|
595
|
+
{
|
|
596
|
+
name: 'viewer',
|
|
597
|
+
permissions: [
|
|
598
|
+
{ resource: 'documents', actions: ['read'] },
|
|
599
|
+
{ resource: 'comments', actions: ['read', 'create'] }
|
|
600
|
+
]
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
name: 'editor',
|
|
604
|
+
inherits: ['viewer'],
|
|
605
|
+
permissions: [
|
|
606
|
+
{ resource: 'documents', actions: ['read', 'write', 'delete'] },
|
|
607
|
+
{
|
|
608
|
+
resource: 'documents',
|
|
609
|
+
actions: ['publish'],
|
|
610
|
+
conditions: [{ type: 'ownership', field: 'authorId' }]
|
|
611
|
+
}
|
|
612
|
+
]
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
name: 'admin',
|
|
616
|
+
inherits: ['editor'],
|
|
617
|
+
permissions: [
|
|
618
|
+
{ resource: 'users', actions: ['read', 'write', 'delete'] },
|
|
619
|
+
{ resource: 'settings', actions: ['read', 'write'] }
|
|
620
|
+
]
|
|
621
|
+
}
|
|
622
|
+
];
|
|
623
|
+
|
|
624
|
+
// Session Security
|
|
625
|
+
class SecureSessionManager {
|
|
626
|
+
private readonly SESSION_DURATION = 3600; // 1 hour
|
|
627
|
+
private readonly REFRESH_THRESHOLD = 300; // 5 minutes
|
|
628
|
+
|
|
629
|
+
async createSession(userId: string, metadata: SessionMetadata): Promise<Session> {
|
|
630
|
+
const sessionId = this.generateSecureId();
|
|
631
|
+
const session: Session = {
|
|
632
|
+
id: sessionId,
|
|
633
|
+
userId,
|
|
634
|
+
createdAt: new Date(),
|
|
635
|
+
expiresAt: new Date(Date.now() + this.SESSION_DURATION * 1000),
|
|
636
|
+
metadata: {
|
|
637
|
+
...metadata,
|
|
638
|
+
userAgent: metadata.userAgent,
|
|
639
|
+
ipAddress: metadata.ipAddress,
|
|
640
|
+
mfaVerified: false
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
await this.store.set(sessionId, session);
|
|
645
|
+
return session;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
async validateSession(sessionId: string, request: Request): Promise<Session | null> {
|
|
649
|
+
const session = await this.store.get(sessionId);
|
|
650
|
+
|
|
651
|
+
if (!session) return null;
|
|
652
|
+
|
|
653
|
+
// Check expiration
|
|
654
|
+
if (new Date() > session.expiresAt) {
|
|
655
|
+
await this.invalidateSession(sessionId);
|
|
656
|
+
return null;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Validate session binding (prevent session hijacking)
|
|
660
|
+
if (!this.validateSessionBinding(session, request)) {
|
|
661
|
+
await this.invalidateSession(sessionId);
|
|
662
|
+
await this.alertSecurityTeam('session_hijacking_attempt', session);
|
|
663
|
+
return null;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// Refresh if close to expiry
|
|
667
|
+
if (this.shouldRefresh(session)) {
|
|
668
|
+
await this.refreshSession(session);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
return session;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
private validateSessionBinding(session: Session, request: Request): boolean {
|
|
675
|
+
// Check IP address consistency (with some tolerance for mobile)
|
|
676
|
+
const currentIp = request.headers.get('x-forwarded-for');
|
|
677
|
+
if (session.metadata.ipAddress !== currentIp) {
|
|
678
|
+
// Log but allow if user agent matches (mobile networks change IPs)
|
|
679
|
+
if (session.metadata.userAgent !== request.headers.get('user-agent')) {
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
return true;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
### 7. Cross-Cutting: Monitoring and Detection
|
|
689
|
+
|
|
690
|
+
```typescript
|
|
691
|
+
/**
|
|
692
|
+
* Security Monitoring: Detect and respond to threats
|
|
693
|
+
*/
|
|
694
|
+
|
|
695
|
+
interface SecurityEvent {
|
|
696
|
+
timestamp: Date;
|
|
697
|
+
eventType: SecurityEventType;
|
|
698
|
+
severity: 'low' | 'medium' | 'high' | 'critical';
|
|
699
|
+
source: string;
|
|
700
|
+
target: string;
|
|
701
|
+
details: Record<string, unknown>;
|
|
702
|
+
userId?: string;
|
|
703
|
+
ipAddress?: string;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
type SecurityEventType =
|
|
707
|
+
| 'authentication_failure'
|
|
708
|
+
| 'authorization_failure'
|
|
709
|
+
| 'rate_limit_exceeded'
|
|
710
|
+
| 'suspicious_pattern'
|
|
711
|
+
| 'data_access_anomaly'
|
|
712
|
+
| 'configuration_change'
|
|
713
|
+
| 'privilege_escalation'
|
|
714
|
+
| 'sql_injection_attempt'
|
|
715
|
+
| 'xss_attempt';
|
|
716
|
+
|
|
717
|
+
class SecurityMonitoring {
|
|
718
|
+
private readonly alertThresholds = {
|
|
719
|
+
authentication_failure: { count: 5, windowMinutes: 5 },
|
|
720
|
+
rate_limit_exceeded: { count: 10, windowMinutes: 1 },
|
|
721
|
+
sql_injection_attempt: { count: 1, windowMinutes: 1 }
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
async logSecurityEvent(event: SecurityEvent): Promise<void> {
|
|
725
|
+
// 1. Store the event
|
|
726
|
+
await this.eventStore.insert(event);
|
|
727
|
+
|
|
728
|
+
// 2. Check for alerting conditions
|
|
729
|
+
await this.checkAlertConditions(event);
|
|
730
|
+
|
|
731
|
+
// 3. Update metrics
|
|
732
|
+
this.metrics.increment(`security_events_${event.eventType}`, {
|
|
733
|
+
severity: event.severity
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
private async checkAlertConditions(event: SecurityEvent): Promise<void> {
|
|
738
|
+
const threshold = this.alertThresholds[event.eventType];
|
|
739
|
+
if (!threshold) return;
|
|
740
|
+
|
|
741
|
+
const recentCount = await this.countRecentEvents(
|
|
742
|
+
event.eventType,
|
|
743
|
+
event.source,
|
|
744
|
+
threshold.windowMinutes
|
|
745
|
+
);
|
|
746
|
+
|
|
747
|
+
if (recentCount >= threshold.count) {
|
|
748
|
+
await this.triggerAlert({
|
|
749
|
+
type: 'threshold_exceeded',
|
|
750
|
+
event,
|
|
751
|
+
count: recentCount,
|
|
752
|
+
threshold: threshold.count
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
async detectAnomalies(): Promise<Anomaly[]> {
|
|
758
|
+
const anomalies: Anomaly[] = [];
|
|
759
|
+
|
|
760
|
+
// Check for unusual access patterns
|
|
761
|
+
const accessPatterns = await this.analyzeAccessPatterns();
|
|
762
|
+
anomalies.push(...accessPatterns.filter(p => p.isAnomalous));
|
|
763
|
+
|
|
764
|
+
// Check for privilege escalation attempts
|
|
765
|
+
const privilegeEvents = await this.analyzePrivilegeEvents();
|
|
766
|
+
anomalies.push(...privilegeEvents.filter(e => e.isAnomalous));
|
|
767
|
+
|
|
768
|
+
// Check for data exfiltration patterns
|
|
769
|
+
const dataAccess = await this.analyzeDataAccessPatterns();
|
|
770
|
+
anomalies.push(...dataAccess.filter(d => d.isAnomalous));
|
|
771
|
+
|
|
772
|
+
return anomalies;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
## Use Cases
|
|
778
|
+
|
|
779
|
+
### Complete API Security Stack
|
|
780
|
+
|
|
781
|
+
```typescript
|
|
782
|
+
// Combining all layers in an Express application
|
|
783
|
+
import express from 'express';
|
|
784
|
+
|
|
785
|
+
const app = express();
|
|
786
|
+
|
|
787
|
+
// Layer 1: Rate limiting (Perimeter)
|
|
788
|
+
app.use(rateLimit({
|
|
789
|
+
windowMs: 60 * 1000,
|
|
790
|
+
max: 100,
|
|
791
|
+
standardHeaders: true,
|
|
792
|
+
legacyHeaders: false
|
|
793
|
+
}));
|
|
794
|
+
|
|
795
|
+
// Layer 2: Security headers (Network/Application)
|
|
796
|
+
app.use(helmet());
|
|
797
|
+
app.use(cors({ origin: allowedOrigins, credentials: true }));
|
|
798
|
+
|
|
799
|
+
// Layer 3: Request validation (Application)
|
|
800
|
+
app.use(express.json({ limit: '100kb' }));
|
|
801
|
+
|
|
802
|
+
// Layer 4: Authentication (Identity)
|
|
803
|
+
app.use(authMiddleware);
|
|
804
|
+
|
|
805
|
+
// Layer 5: Authorization per route (Identity)
|
|
806
|
+
app.get('/api/users/:id',
|
|
807
|
+
authorize(['admin', 'self']),
|
|
808
|
+
async (req, res) => {
|
|
809
|
+
// Layer 6: Data access with security context
|
|
810
|
+
const user = await secureDataAccess.getUser(req.params.id, req.securityContext);
|
|
811
|
+
res.json(user);
|
|
812
|
+
}
|
|
813
|
+
);
|
|
814
|
+
|
|
815
|
+
// Cross-cutting: Error handling with security logging
|
|
816
|
+
app.use(securityErrorHandler);
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
## Best Practices
|
|
820
|
+
|
|
821
|
+
### Do's
|
|
822
|
+
|
|
823
|
+
- **Implement all layers** - each provides unique protection
|
|
824
|
+
- **Fail securely** - deny access when in doubt
|
|
825
|
+
- **Log security events** for detection and forensics
|
|
826
|
+
- **Rotate credentials** regularly
|
|
827
|
+
- **Validate all inputs** at every layer
|
|
828
|
+
- **Encrypt sensitive data** at rest and in transit
|
|
829
|
+
- **Use least privilege** for all access
|
|
830
|
+
- **Test security controls** regularly
|
|
831
|
+
- **Keep dependencies updated** for security patches
|
|
832
|
+
|
|
833
|
+
### Don'ts
|
|
834
|
+
|
|
835
|
+
- Don't rely on a single security layer
|
|
836
|
+
- Don't trust user input at any layer
|
|
837
|
+
- Don't expose detailed error messages
|
|
838
|
+
- Don't store secrets in code
|
|
839
|
+
- Don't skip security in development
|
|
840
|
+
- Don't ignore security alerts
|
|
841
|
+
- Don't assume internal traffic is safe
|
|
842
|
+
- Don't disable security for "convenience"
|
|
843
|
+
|
|
844
|
+
## References
|
|
845
|
+
|
|
846
|
+
- [OWASP Security Cheat Sheets](https://cheatsheetseries.owasp.org/)
|
|
847
|
+
- [NIST Cybersecurity Framework](https://www.nist.gov/cyberframework)
|
|
848
|
+
- [AWS Well-Architected Security Pillar](https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/)
|
|
849
|
+
- [Zero Trust Architecture](https://www.nist.gov/publications/zero-trust-architecture)
|