trading-platform/docs/SECURITY.md

814 lines
18 KiB
Markdown

# Security Guide
## Overview
OrbiQuant IA maneja datos financieros sensibles (fondos de usuarios, órdenes de trading, información personal) por lo que la seguridad es **crítica**. Este documento describe las medidas de seguridad implementadas y best practices.
## Threat Model
### Assets to Protect
1. **User Funds:** Dinero en wallets internos y exchanges
2. **Personal Data:** Email, nombre, dirección, documentos KYC
3. **Trading Data:** Posiciones, órdenes, estrategias
4. **API Keys:** Claves de exchanges de usuarios
5. **Financial Data:** Transacciones, balances, historial
6. **ML Models:** Modelos propietarios de predicción
### Attack Vectors
1. **Credential Theft:** Phishing, keyloggers, brute force
2. **API Abuse:** Rate limiting bypass, scraping, DDoS
3. **SQL Injection:** Malicious queries
4. **XSS:** Cross-site scripting attacks
5. **CSRF:** Cross-site request forgery
6. **Man-in-the-Middle:** Traffic interception
7. **Insider Threats:** Malicious employees
8. **Supply Chain:** Compromised dependencies
## Authentication & Authorization
### Multi-Factor Authentication (MFA)
**Implementation:** TOTP (Time-based One-Time Password) using Speakeasy
```typescript
// Enable 2FA
POST /api/auth/2fa/enable
Response: {
"secret": "JBSWY3DPEHPK3PXP",
"qrCode": "data:image/png;base64,..."
}
// Verify 2FA setup
POST /api/auth/2fa/verify
{
"token": "123456"
}
// Login with 2FA
POST /api/auth/login
{
"email": "user@example.com",
"password": "password",
"totpCode": "123456" // Required if 2FA enabled
}
```
**Enforcement:**
- Mandatory for withdrawals > $1000
- Mandatory for API key generation
- Mandatory for admin accounts
- Optional for regular trading
### OAuth2 Integration
**Supported Providers:**
- Google (OAuth 2.0)
- Facebook
- Apple Sign-In
- GitHub
**Security Features:**
- State parameter for CSRF protection
- PKCE (Proof Key for Code Exchange) for mobile
- Token validation with provider APIs
- Automatic account linking
```typescript
// OAuth flow
GET /api/auth/oauth/google
Redirects to Google
User authorizes
Callback to /api/auth/oauth/google/callback
Validates state and code
Exchanges code for tokens
Creates/links user account
Returns JWT
```
### JWT (JSON Web Tokens)
**Token Types:**
1. **Access Token**
- Lifetime: 1 hour
- Used for API requests
- Stored in memory (not localStorage)
2. **Refresh Token**
- Lifetime: 30 days
- Used to get new access tokens
- Stored in httpOnly cookie
- Rotation on each use
**Token Structure:**
```json
{
"header": {
"alg": "HS256",
"typ": "JWT"
},
"payload": {
"sub": "user-uuid",
"email": "user@example.com",
"role": "user",
"iat": 1670832000,
"exp": 1670835600
},
"signature": "..."
}
```
**Security Measures:**
- Strong secret (256-bit minimum)
- Short-lived access tokens
- Refresh token rotation
- Token revocation on logout
- Blacklist for compromised tokens
### Role-Based Access Control (RBAC)
**Roles:**
| Role | Permissions |
|------|-------------|
| **user** | Trading, portfolio, courses |
| **premium** | Advanced features, higher limits |
| **trader** | Create strategies, copy trading |
| **admin** | User management, system config |
| **super_admin** | Full system access |
**Permission Checking:**
```typescript
// Middleware
const requireRole = (roles: string[]) => {
return (req, res, next) => {
if (!roles.includes(req.user.role)) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
};
// Usage
router.post('/admin/users', requireRole(['admin', 'super_admin']), createUser);
```
### Session Management
**Features:**
- Device tracking (browser, OS, IP)
- Active session list
- Concurrent session limits (max 5)
- Session revocation (logout other devices)
- Automatic logout after 24h inactivity
```typescript
GET /api/auth/sessions
Response: {
"sessions": [
{
"id": "session-uuid",
"device": "Chrome on Windows",
"ip": "192.168.1.1",
"lastActivity": "2025-12-12T10:00:00Z",
"current": true
}
]
}
DELETE /api/auth/sessions/:sessionId // Logout specific session
DELETE /api/auth/sessions // Logout all except current
```
## Data Protection
### Encryption at Rest
**Database:**
- PostgreSQL with pgcrypto extension
- Encrypted columns for sensitive data:
- API keys (AES-256)
- Social security numbers
- Bank account numbers
- Private keys
```sql
-- Encrypt API key
UPDATE users
SET exchange_api_key = pgp_sym_encrypt('secret_key', 'encryption_password');
-- Decrypt API key
SELECT pgp_sym_decrypt(exchange_api_key, 'encryption_password')
FROM users WHERE id = 'user-uuid';
```
**File Storage:**
- KYC documents encrypted with AES-256
- Encryption keys stored in AWS KMS (future)
- Per-user encryption keys
### Encryption in Transit
**TLS/SSL:**
- Enforce HTTPS in production
- TLS 1.3 minimum
- Strong cipher suites only
- HSTS (HTTP Strict Transport Security)
**Certificate Management:**
- Let's Encrypt for SSL certificates
- Auto-renewal with Certbot
- Certificate pinning for mobile apps
```nginx
# Nginx configuration
server {
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/orbiquant.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/orbiquant.com/privkey.pem;
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
```
### Password Security
**Hashing:**
- Algorithm: bcrypt
- Salt rounds: 12
- Automatic rehashing on login if rounds < 12
```typescript
import bcrypt from 'bcryptjs';
// Hash password
const hash = await bcrypt.hash(password, 12);
// Verify password
const isValid = await bcrypt.compare(password, hash);
```
**Password Policy:**
- Minimum 8 characters
- At least 1 uppercase letter
- At least 1 lowercase letter
- At least 1 number
- At least 1 special character
- Not in common password list
- Cannot be same as email
**Password Reset:**
- Token valid for 1 hour only
- One-time use tokens
- Email verification required
- Rate limited (3 attempts per hour)
### API Key Security
**User API Keys (for exchanges):**
- Encrypted at rest (AES-256)
- Never logged
- Permissions scope (read-only vs trading)
- IP whitelisting option
- Automatic rotation reminders
**Platform API Keys (internal services):**
- Separate keys per service
- Stored in environment variables
- Rotated every 90 days
- Revoked immediately if compromised
**Best Practices:**
```typescript
// ❌ Bad
const apiKey = "sk_live_1234567890";
logger.info(`Using API key: ${apiKey}`);
// ✅ Good
const apiKey = process.env.EXCHANGE_API_KEY;
logger.info('Exchange API key loaded');
```
## Input Validation & Sanitization
### Schema Validation
Using Zod for runtime type checking:
```typescript
import { z } from 'zod';
const OrderSchema = z.object({
symbol: z.string().regex(/^[A-Z]{6,10}$/),
side: z.enum(['BUY', 'SELL']),
type: z.enum(['MARKET', 'LIMIT', 'STOP_LOSS']),
quantity: z.number().positive().max(1000000),
price: z.number().positive().optional(),
});
// Validate input
const validatedOrder = OrderSchema.parse(req.body);
```
### SQL Injection Prevention
**ORM (TypeORM):**
- Parameterized queries by default
- Never use raw queries with user input
- Input validation before queries
```typescript
// ❌ Bad (SQL Injection vulnerable)
const users = await db.query(`SELECT * FROM users WHERE email = '${email}'`);
// ✅ Good (Parameterized)
const users = await userRepository.find({ where: { email } });
```
### XSS Prevention
**Frontend:**
- React auto-escapes by default
- DOMPurify for user-generated HTML
- CSP (Content Security Policy) headers
**Backend:**
- Sanitize HTML in user inputs
- Escape output in templates
- Set secure headers (Helmet.js)
```typescript
import helmet from 'helmet';
import DOMPurify from 'dompurify';
// Helmet middleware
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
}));
// Sanitize HTML
const cleanHTML = DOMPurify.sanitize(userInput);
```
### CSRF Protection
**Token-based:**
- CSRF tokens for state-changing requests
- SameSite cookie attribute
- Double-submit cookie pattern
```typescript
// Generate CSRF token
const csrfToken = crypto.randomBytes(32).toString('hex');
req.session.csrfToken = csrfToken;
// Validate CSRF token
if (req.body.csrfToken !== req.session.csrfToken) {
return res.status(403).json({ error: 'Invalid CSRF token' });
}
```
## Rate Limiting & DDoS Protection
### API Rate Limiting
**Implementation:** express-rate-limit
```typescript
import rateLimit from 'express-rate-limit';
// General rate limit
const generalLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 100, // 100 requests per minute
message: 'Too many requests, please try again later',
standardHeaders: true,
legacyHeaders: false,
});
// Auth rate limit (stricter)
const authLimiter = rateLimit({
windowMs: 60 * 1000,
max: 5,
skipSuccessfulRequests: true, // Only count failed attempts
});
// Trading rate limit
const tradingLimiter = rateLimit({
windowMs: 60 * 1000,
max: 60,
keyGenerator: (req) => req.user.id, // Per user
});
app.use('/api', generalLimiter);
app.use('/api/auth', authLimiter);
app.use('/api/trading', tradingLimiter);
```
### DDoS Protection
**Cloudflare (recommended for production):**
- DDoS mitigation
- WAF (Web Application Firewall)
- Bot detection
- Rate limiting at edge
**Nginx:**
```nginx
# Connection limits
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 10;
# Request rate limiting
limit_req_zone $binary_remote_addr zone=req:10m rate=10r/s;
limit_req zone=req burst=20 nodelay;
```
## Payment Security
### Stripe Integration
**PCI Compliance:**
- Never store credit card numbers
- Use Stripe.js for card tokenization
- PCI DSS SAQ-A compliance
**Webhook Security:**
```typescript
// Verify Stripe webhook signature
const signature = req.headers['stripe-signature'];
const event = stripe.webhooks.constructEvent(
req.body,
signature,
process.env.STRIPE_WEBHOOK_SECRET
);
if (event.type === 'payment_intent.succeeded') {
// Handle payment
}
```
**Best Practices:**
- Idempotency keys for payment retries
- 3D Secure for high-value transactions
- Fraud detection (Stripe Radar)
- Refund policies
### Cryptocurrency Payments (Future)
**Security Considerations:**
- HD wallets (Hierarchical Deterministic)
- Multi-signature wallets
- Cold storage for majority of funds
- Hot wallet limits ($10k max)
## Audit Logging
### What to Log
**Security Events:**
- Login attempts (success/failure)
- Password changes
- 2FA enable/disable
- API key creation/revocation
- Permission changes
- Suspicious activity
**Financial Events:**
- Deposits/withdrawals
- Trades
- Order placements
- Balance changes
**System Events:**
- Errors
- Service failures
- Database queries (slow/failed)
### Log Format
```json
{
"timestamp": "2025-12-12T10:00:00.000Z",
"level": "info",
"event": "login_success",
"userId": "user-uuid",
"ip": "192.168.1.1",
"userAgent": "Mozilla/5.0...",
"metadata": {
"2faUsed": true,
"device": "Chrome on Windows"
}
}
```
### Log Storage
**Database Table:** `audit.api_logs`
```sql
CREATE TABLE audit.api_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
user_id UUID REFERENCES auth.users(id),
event_type VARCHAR(100) NOT NULL,
ip_address INET,
user_agent TEXT,
request_path TEXT,
request_method VARCHAR(10),
status_code INTEGER,
response_time_ms INTEGER,
metadata JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_api_logs_user_id ON audit.api_logs(user_id);
CREATE INDEX idx_api_logs_timestamp ON audit.api_logs(timestamp);
CREATE INDEX idx_api_logs_event_type ON audit.api_logs(event_type);
```
### Log Retention
- Security logs: 1 year
- Transaction logs: 7 years (regulatory)
- System logs: 90 days
- Archived to S3 after 30 days
## Dependency Security
### npm audit
```bash
# Check for vulnerabilities
npm audit
# Fix vulnerabilities automatically
npm audit fix
# Force fix (may introduce breaking changes)
npm audit fix --force
```
### Automated Scanning
**GitHub Dependabot:**
- Automatic PRs for security updates
- Weekly vulnerability scans
**Snyk:**
- Real-time vulnerability monitoring
- License compliance checking
```yaml
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/apps/backend"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
```
### Supply Chain Security
**Best Practices:**
- Lock file commits (package-lock.json)
- Verify package integrity (npm signatures)
- Use package-lock.json for reproducible builds
- Review new dependencies carefully
- Minimize dependencies
## Infrastructure Security
### Server Hardening
**Firewall (ufw):**
```bash
# Allow only necessary ports
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp # SSH
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
ufw enable
```
**SSH:**
```bash
# Disable password authentication
PasswordAuthentication no
PubkeyAuthentication yes
# Disable root login
PermitRootLogin no
# Change default port
Port 2222
```
**Automatic Updates:**
```bash
# Ubuntu
apt install unattended-upgrades
dpkg-reconfigure --priority=low unattended-upgrades
```
### Database Security
**PostgreSQL:**
```sql
-- Create dedicated user with limited permissions
CREATE USER orbiquant_app WITH PASSWORD 'strong_password';
GRANT CONNECT ON DATABASE orbiquant_platform TO orbiquant_app;
GRANT USAGE ON SCHEMA auth, trading TO orbiquant_app;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA auth, trading TO orbiquant_app;
-- Revoke public access
REVOKE ALL ON DATABASE orbiquant_platform FROM PUBLIC;
-- Enable SSL
ssl = on
ssl_cert_file = '/path/to/server.crt'
ssl_key_file = '/path/to/server.key'
```
**Redis:**
```conf
# Require password
requirepass strong_redis_password
# Bind to localhost only
bind 127.0.0.1
# Disable dangerous commands
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG ""
```
### Container Security
**Docker:**
```dockerfile
# Use non-root user
FROM node:18-alpine
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
USER nodejs
# Read-only file system
docker run --read-only ...
# Drop capabilities
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE ...
```
**Docker Compose:**
```yaml
services:
backend:
image: orbiquant-backend
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
```
## Compliance & Regulations
### GDPR (General Data Protection Regulation)
**Requirements:**
- Data minimization
- Right to access (download data)
- Right to erasure (delete account)
- Data portability
- Consent management
**Implementation:**
```typescript
// Export user data
GET /api/users/me/export
Response: JSON file with all user data
// Delete account (GDPR)
DELETE /api/users/me
- Anonymize user data
- Delete PII (personally identifiable information)
- Keep transaction history (regulatory)
```
### KYC/AML (Know Your Customer / Anti-Money Laundering)
**Verification Levels:**
| Level | Limits | Requirements |
|-------|--------|--------------|
| **Level 0** | $100/day | Email verification |
| **Level 1** | $1,000/day | Name, DOB, address |
| **Level 2** | $10,000/day | ID document, selfie |
| **Level 3** | Unlimited | Proof of address, video call |
**Monitoring:**
- Suspicious transaction patterns
- Large withdrawals
- Rapid account changes
- Regulatory reporting
## Incident Response
### Security Incident Procedure
1. **Detection:** Monitoring alerts, user reports
2. **Containment:** Isolate affected systems
3. **Investigation:** Root cause analysis
4. **Remediation:** Fix vulnerability, patch systems
5. **Recovery:** Restore normal operations
6. **Post-Mortem:** Document lessons learned
### Breach Notification
**Timeline:**
- Internal notification: Immediate
- User notification: Within 72 hours
- Regulatory notification: As required by law
**Template:**
```
Subject: Security Incident Notification
We are writing to inform you of a security incident that may have affected your account.
What happened: [Description]
What data was affected: [List]
What we are doing: [Actions taken]
What you should do: [User actions]
We sincerely apologize for this incident.
```
## Security Checklist
### Development
- [ ] Input validation on all endpoints
- [ ] Parameterized SQL queries
- [ ] Error messages don't leak sensitive info
- [ ] Secrets in environment variables
- [ ] Dependencies scanned for vulnerabilities
- [ ] Code review before merge
- [ ] No hardcoded credentials
### Deployment
- [ ] HTTPS enforced
- [ ] Security headers configured (Helmet)
- [ ] Rate limiting enabled
- [ ] CORS properly configured
- [ ] Database backups enabled
- [ ] Logging configured
- [ ] Monitoring alerts set up
### Operations
- [ ] Rotate API keys every 90 days
- [ ] Review access logs weekly
- [ ] Security patches applied within 48h
- [ ] Backup tested monthly
- [ ] Incident response plan updated
- [ ] Team security training quarterly
## Security Contacts
**Report vulnerabilities:** security@orbiquant.com
**Bug Bounty Program (future):**
- $100-$5000 depending on severity
- Responsible disclosure required
## References
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [OWASP API Security](https://owasp.org/www-project-api-security/)
- [CWE Top 25](https://cwe.mitre.org/top25/)
- [PCI DSS](https://www.pcisecuritystandards.org/)
- [GDPR](https://gdpr.eu/)
- [Stripe Security](https://stripe.com/docs/security)