306 lines
8.9 KiB
Markdown
306 lines
8.9 KiB
Markdown
---
|
|
trigger: always_on
|
|
---
|
|
|
|
|
|
# Security Patterns for GoodGo Microservices
|
|
|
|
## When to Use This Skill
|
|
|
|
Use this skill when:
|
|
- Implementing authentication and authorization in any service
|
|
- Protecting sensitive data (PII, credentials, tokens)
|
|
- Validating user inputs and file uploads
|
|
- Implementing rate limiting and DDoS protection
|
|
- Setting up audit logging and security monitoring
|
|
- Encrypting data at rest and in transit
|
|
- Managing secrets and credentials
|
|
- Implementing security testing
|
|
- Handling security incidents
|
|
- Designing secure API endpoints
|
|
|
|
## Core Security Principles
|
|
|
|
1. **Defense in Depth**: Multiple layers of security controls
|
|
2. **Least Privilege**: Grant minimum required permissions
|
|
3. **Fail Secure**: Default to deny access
|
|
4. **Separation of Duties**: Critical operations require multiple approvals
|
|
5. **Audit Everything**: Log all security-relevant events
|
|
6. **Encrypt Sensitive Data**: PII, tokens, credentials must be encrypted
|
|
7. **Validate All Inputs**: Never trust user input
|
|
8. **Principle of Least Exposure**: Minimize attack surface
|
|
9. **Secure by Default**: Security built-in, not bolted on
|
|
10. **Assume Breach**: Design for detection and response
|
|
|
|
## Authentication & Authorization
|
|
|
|
### JWT Token Validation
|
|
|
|
Extract tokens from Authorization header or cookies, verify with `jwtService.verifyAccessToken()`, and attach user payload to request. Return 401 for missing/invalid tokens.
|
|
|
|
```typescript
|
|
// Key pattern - see references/REFERENCE.md for full implementation
|
|
const authHeader = req.headers.authorization;
|
|
const token = authHeader?.startsWith('Bearer ') ? authHeader.substring(7) : req.cookies?.access_token;
|
|
const payload = await jwtService.verifyAccessToken(token);
|
|
req.user = { id: payload.sub, roles: payload.roles || [], permissions: payload.permissions || [] };
|
|
```
|
|
|
|
### Role-Based Authorization (RBAC)
|
|
|
|
Use `requireRole()` middleware for role checks and `requirePermission()` for fine-grained access control with `resource:action` format.
|
|
|
|
```typescript
|
|
// Usage pattern
|
|
router.post('/api/v1/users', authenticate(), requirePermission('users', 'create'), userController.create);
|
|
router.delete('/api/v1/admin', authenticate(), requireRole('admin', 'superadmin'), adminController.delete);
|
|
```
|
|
|
|
### Resource Ownership
|
|
|
|
Validate users can only access their own resources using `requireOwnership()` middleware.
|
|
|
|
## Data Protection
|
|
|
|
### Encryption
|
|
|
|
- Use AES-256-GCM for encrypting PII at rest
|
|
- Store encrypted data as `iv:tag:ciphertext` format
|
|
- Require 32+ character ENCRYPTION_KEY
|
|
|
|
### Password Hashing
|
|
|
|
- Always use bcrypt with cost factor 12 in production
|
|
- Never log passwords - sanitize before logging
|
|
|
|
### Token Storage
|
|
|
|
- Hash tokens with SHA-256 before database storage
|
|
- Use `crypto.randomBytes(32)` for secure token generation
|
|
|
|
## Input Validation
|
|
|
|
### Zod Schema Validation
|
|
|
|
Always validate inputs with Zod schemas before processing:
|
|
|
|
```typescript
|
|
const CreateUserDto = z.object({
|
|
email: z.string().email(),
|
|
password: z.string().min(8).regex(/[A-Z]/).regex(/[a-z]/).regex(/[0-9]/).regex(/[^A-Za-z0-9]/),
|
|
phone: z.string().regex(/^\+[1-9]\d{1,14}$/).optional(),
|
|
name: z.string().min(1).max(255)
|
|
});
|
|
|
|
// In controller
|
|
const dto = CreateUserDto.parse(req.body);
|
|
```
|
|
|
|
### File Upload Validation
|
|
|
|
- Check file size (max 10MB default)
|
|
- Validate MIME type against whitelist
|
|
- Verify content with `file-type` library to prevent MIME spoofing
|
|
|
|
### SQL Injection Prevention
|
|
|
|
Always use Prisma parameterized queries - never string concatenation for queries.
|
|
|
|
## Rate Limiting
|
|
|
|
Configure Redis-backed rate limiting for all endpoints:
|
|
|
|
| Limiter Type | Window | Max Requests | Use Case |
|
|
|-------------|--------|--------------|----------|
|
|
| Standard | 15 min | 100 | General API endpoints |
|
|
| Strict | 1 hour | 10 | Sensitive operations |
|
|
| Login | 15 min | 5 | Authentication endpoints |
|
|
|
|
```typescript
|
|
router.post('/api/v1/auth/login', loginLimiter, authController.login);
|
|
```
|
|
|
|
## Security Headers
|
|
|
|
Use Helmet middleware with CSP, HSTS, and additional headers:
|
|
- `X-Content-Type-Options: nosniff`
|
|
- `X-Frame-Options: DENY`
|
|
- `X-XSS-Protection: 1; mode=block`
|
|
- `Referrer-Policy: strict-origin-when-cross-origin`
|
|
|
|
## CORS Configuration
|
|
|
|
- Whitelist allowed origins from environment variables
|
|
- Enable credentials for authenticated requests
|
|
- Set `maxAge: 86400` (24 hours) for preflight caching
|
|
|
|
## Secrets Management
|
|
|
|
- Never hardcode secrets - use environment variables
|
|
- Validate secrets with Zod schema at startup
|
|
- Use secret managers in production (AWS Secrets Manager, Vault, etc.)
|
|
- Rotate secrets quarterly
|
|
|
|
```typescript
|
|
const secretsSchema = z.object({
|
|
JWT_SECRET: z.string().min(32),
|
|
DATABASE_URL: z.string().url(),
|
|
ENCRYPTION_KEY: z.string().min(32).optional()
|
|
});
|
|
```
|
|
|
|
## Audit Logging
|
|
|
|
Log all security-relevant events with sanitized details:
|
|
|
|
```typescript
|
|
await auditService.logSecurityEvent('LOGIN_SUCCESS', user.id, { email: user.email }, req);
|
|
await auditService.logSecurityEvent('PERMISSION_DENIED', user.id, { resource, action }, req);
|
|
```
|
|
|
|
Sanitize sensitive fields: password, token, secret, ssn, creditCard.
|
|
|
|
## Error Handling
|
|
|
|
- Log full errors internally
|
|
- Never expose user existence (use generic "Invalid credentials")
|
|
- Show stack traces only in development
|
|
- Return sanitized error codes in production
|
|
|
|
## Security Testing
|
|
|
|
Write tests for:
|
|
- SQL injection prevention
|
|
- XSS attack prevention
|
|
- Authentication enforcement
|
|
- Authorization enforcement
|
|
- Rate limiting effectiveness
|
|
|
|
## Best Practices
|
|
|
|
- All endpoints require authentication (except public)
|
|
- Authorization checks at every protected route
|
|
- Input validation with Zod on all user input
|
|
- Rate limiting on all endpoints
|
|
- Error messages sanitized in production
|
|
- PII encrypted at rest with AES-256-GCM
|
|
- Passwords hashed with bcrypt (cost 12+)
|
|
- Tokens hashed before database storage
|
|
- HTTPS enforced (TLS 1.2+)
|
|
- Security headers via Helmet
|
|
- Audit logging for security events
|
|
- Dependencies scanned for vulnerabilities
|
|
- File uploads validated (size, type, content)
|
|
|
|
## Common Mistakes
|
|
|
|
### 1. Weak Password Hashing
|
|
|
|
```typescript
|
|
// BAD: Low cost factor
|
|
const hash = await bcrypt.hash(password, 8);
|
|
|
|
// GOOD: Use cost 12
|
|
const hash = await bcrypt.hash(password, 12);
|
|
```
|
|
|
|
### 2. Hardcoded Secrets
|
|
|
|
```typescript
|
|
// BAD
|
|
const JWT_SECRET = "my-secret-key";
|
|
|
|
// GOOD
|
|
const JWT_SECRET = process.env.JWT_SECRET;
|
|
if (!JWT_SECRET) throw new Error('JWT_SECRET required');
|
|
```
|
|
|
|
### 3. Missing Input Validation
|
|
|
|
```typescript
|
|
// BAD
|
|
const user = await prisma.user.findUnique({ where: { id: req.params.id } });
|
|
|
|
// GOOD
|
|
const { id } = z.object({ id: z.string().cuid() }).parse(req.params);
|
|
const user = await prisma.user.findUnique({ where: { id } });
|
|
```
|
|
|
|
### 4. Logging Sensitive Data
|
|
|
|
```typescript
|
|
// BAD
|
|
logger.info('User login', { email, password });
|
|
|
|
// GOOD
|
|
logger.info('User login', { email, password: '[REDACTED]' });
|
|
```
|
|
|
|
### 5. Exposing User Existence
|
|
|
|
```typescript
|
|
// BAD
|
|
if (!user) throw new Error('User not found');
|
|
|
|
// GOOD
|
|
if (!user || !await bcrypt.compare(password, user.passwordHash)) {
|
|
throw new Error('Invalid credentials');
|
|
}
|
|
```
|
|
|
|
## Quick Reference
|
|
|
|
| Security Area | Implementation |
|
|
|--------------|----------------|
|
|
| **Password hashing** | `bcrypt.hash(password, 12)` |
|
|
| **JWT Access Token** | 15 minutes expiry |
|
|
| **JWT Refresh Token** | 7 days expiry |
|
|
| **Rate limiting** | Standard: 100/15min, Strict: 10/hour, Login: 5/15min |
|
|
| **Encryption** | AES-256-GCM for PII |
|
|
| **Input validation** | Zod schemas, always parse before use |
|
|
| **SQL injection** | Use Prisma (parameterized by default) |
|
|
| **Security headers** | helmet middleware |
|
|
| **CORS** | Whitelist origins, credentials: true |
|
|
|
|
**Essential Imports:**
|
|
|
|
```typescript
|
|
import bcrypt from 'bcrypt';
|
|
import helmet from 'helmet';
|
|
import rateLimit from 'express-rate-limit';
|
|
import { z } from 'zod';
|
|
import { jwtService } from '@goodgo/auth-sdk';
|
|
```
|
|
|
|
## Security Checklist
|
|
|
|
Before deploying any service:
|
|
|
|
- [ ] All endpoints require authentication (except public)
|
|
- [ ] Authorization checks implemented (RBAC/ABAC)
|
|
- [ ] Input validation with Zod schemas
|
|
- [ ] Rate limiting configured
|
|
- [ ] Error messages sanitized (no info disclosure)
|
|
- [ ] PII encrypted at rest
|
|
- [ ] Passwords hashed with bcrypt (cost 12+)
|
|
- [ ] Tokens hashed before storing
|
|
- [ ] Secrets in environment variables (never hardcoded)
|
|
- [ ] HTTPS enforced (TLS 1.2+)
|
|
- [ ] CORS configured correctly
|
|
- [ ] Security headers set (helmet)
|
|
- [ ] Audit logging enabled
|
|
- [ ] SQL injection prevented (use Prisma)
|
|
- [ ] XSS prevention (input sanitization)
|
|
- [ ] File upload validation
|
|
- [ ] Security tests passing
|
|
- [ ] Dependencies scanned for vulnerabilities
|
|
- [ ] Secrets rotation plan in place
|
|
|
|
## Resources
|
|
|
|
- [Detailed Code Examples](./references/REFERENCE.md) - Full implementation examples
|
|
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
|
- [OWASP API Security Top 10](https://owasp.org/www-project-api-security/)
|
|
- [Node.js Security Best Practices](https://nodejs.org/en/docs/guides/security/)
|
|
- [Express Security Best Practices](https://expressjs.com/en/advanced/best-practice-security.html)
|