trading-platform/docs/90-transversal/security/SECURITY.md
Adrian Flores Cortes bae221db5f docs: Move SECURITY.md to transversal location
Moved docs/SECURITY.md to docs/90-transversal/security/SECURITY.md
to organize security documentation with other transversal docs.

Part of ST3.2 Documentation Purge.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 19:03:25 -06:00

18 KiB

id title type project version updated_date
SECURITY Security Guide Documentation trading-platform 1.0.0 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

// 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
// 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:

{
  "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:

// 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
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
-- 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 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
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:

// ❌ 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:

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
// ❌ 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)
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
// 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

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:

# 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:

// 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

{
  "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

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

# 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
# .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):

# 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:

# Disable password authentication
PasswordAuthentication no
PubkeyAuthentication yes

# Disable root login
PermitRootLogin no

# Change default port
Port 2222

Automatic Updates:

# Ubuntu
apt install unattended-upgrades
dpkg-reconfigure --priority=low unattended-upgrades

Database Security

PostgreSQL:

-- 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:

# 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:

# 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:

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:

// 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