---
id: "SECURITY"
title: "Security Guide"
type: "Documentation"
project: "trading-platform"
version: "1.0.0"
updated_date: "2026-01-04"
---

# Security Guide

## Overview

Trading Platform 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/trading.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/trading.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 trading_app WITH PASSWORD 'strong_password';
GRANT CONNECT ON DATABASE trading_platform TO trading_app;
GRANT USAGE ON SCHEMA auth, trading TO trading_app;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA auth, trading TO trading_app;

-- Revoke public access
REVOKE ALL ON DATABASE trading_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: trading-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@trading.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)
