Security dan Best Practice Backend di Express.js - Perwira Learning Center


1. Latar Belakang

    Memasuki minggu keempat, sesi kelima pembelajaran Express.js di Perwira Learning Center membahas Security dan Best Practice Backend. Ini adalah sistem pertahanan berlapis dalam aplikasi:

Analogi Rumah:

text
┌─────────────────────────────────────────────────────────┐
│                    PERTAHANAN RUMAH                     │
├─────────────────────────────────────────────────────────┤
│                                                        │
│  🔑 ENVIRONMENT VARIABLES = Brankas rahasia           │
│     → Kunci tidak ditaruh di sembarang tempat         │
│                                                        │
│  🚪 CORS = Pintu dengan aturan tamu                  │
│     → Hanya tamu tertentu yang boleh masuk            │
│                                                        │
│  🛡️ HELMET = Pagar dan sistem keamanan               │
│     → Proteksi dari serangan dari luar               │
│                                                        │
│  📜 HTTPS = Amplop surat rahasia                     │
│     → Isi surat tidak bisa dibaca orang lain          │
│                                                        │
│  🧹 SANITIZATION = Membersihkan tamu yang mencurigakan│
│     → Hapus senjata tajam sebelum masuk               │
│                                                        │
│  ⏱️ RATE LIMITING = Batasi jumlah tamu               │
│     → Cegah kerumunan dan serangan massal            │
│                                                        │
└─────────────────────────────────────────────────────────┘

Mengapa Keamanan Backend Penting?

javascript
/**
 * DAMPAK KEAMANAN YANG LEMAH
 * 
 * ❌ TANPA ENV VARIABLE:
 * const DB_PASSWORD = "admin123" // Hardcoded di GitHub!
 * Semua orang bisa lihat password database
 * 
 * ❌ TANPA CORS:
 * Website jahat bisa akses API kita dari domain manapun
 * Script di situs judi bisa curi data user kita
 * 
 * ❌ TANPA HELMET:
 * Header X-Powered-By: Express (kasi tau musuh kita pake apa)
 * Bisa kena XSS, clickjacking, MIME sniffing
 * 
 * ❌ TANPA VALIDASI:
 * User bisa input <script>alert('hacked')</script>
 * Kode jahat jalan di browser admin
 * 
 * ❌ TANPA RATE LIMITING:
 * Attacker bisa spam 10.000 request/detik
 * Server down, semua user tidak bisa akses
 */

2. Alat dan Bahan

a. Perangkat Lunak

  1. Node.js & npm - Runtime dan package manager
  2. Express.js - Framework utama
  3. dotenv - Environment variables management
  4. cors - Cross-Origin Resource Sharing
  5. helmet - Security headers middleware
  6. express-rate-limit - Rate limiting
  7. express-slow-down - Slow down attacks
  8. csurf - CSRF protection
  9. xss-clean - XSS sanitization
  10. hpp - HTTP Parameter Pollution protection
  11. compression - Response compression
  12. express-mongo-sanitize - NoSQL injection prevention
  13. Postman - Security testing
  14. OWASP ZAP - Security scanning (optional)

b. Perangkat Keras

  1. Laptop/PC dengan spesifikasi standar

3. Pembahasan

3.1 Security Layer Architecture

javascript
/**
 * ARSITEKTUR KEAMANAN BERLAPIS
 * 
 * ┌─────────────────────────────────────────────────────┐
 * │                  LAYER 7: HTTPS                     │
 * │              Encrypted Communication                │
 * └─────────────────────┬───────────────────────────────┘
 *                       │
 * ┌─────────────────────▼───────────────────────────────┐
 * │                  LAYER 6: RATE LIMITING             │
 * │           Prevent Brute Force & DDoS               │
 * └─────────────────────┬───────────────────────────────┘
 *                       │
 * ┌─────────────────────▼───────────────────────────────┐
 * │                  LAYER 5: CORS                      │
 * │            Cross-Origin Access Control              │
 * └─────────────────────┬───────────────────────────────┘
 *                       │
 * ┌─────────────────────▼───────────────────────────────┐
 * │                  LAYER 4: HELMET                    │
 * │           Security Headers (HSTS, CSP, etc)        │
 * └─────────────────────┬───────────────────────────────┘
 *                       │
 * ┌─────────────────────▼───────────────────────────────┐
 * │                  LAYER 3: CSRF PROTECTION           │
 * │           Prevent Cross-Site Request Forgery       │
 * └─────────────────────┬───────────────────────────────┘
 *                       │
 * ┌─────────────────────▼───────────────────────────────┐
 * │                  LAYER 2: INPUT VALIDATION          │
 * │          XSS, SQL/NoSQL Injection Prevention       │
 * └─────────────────────┬───────────────────────────────┘
 *                       │
 * ┌─────────────────────▼───────────────────────────────┐
 * │                  LAYER 1: AUTHENTICATION            │
 * │          JWT, Session, API Key, OAuth              │
 * └─────────────────────────────────────────────────────┘
 * 
 * 🎯 SETIAP LAYER PERTAHANAN = SALAH SATU KEGAGALAN
 *    TIDAK MEMBUAT SELURUH SISTEM RENTAN!
 */

3.2 Praktik Lengkap: Secure Express.js Boilerplate

Mari kita bangun aplikasi Express.js dengan standar keamanan enterprise:

bash
# 1. Buat folder project
mkdir secure-express-api
cd secure-express-api

# 2. Inisialisasi project
npm init -y

# 3. Install dependencies keamanan
npm install express dotenv cors helmet express-rate-limit
npm install express-slow-down csurf cookie-parser
npm install xss-clean hpp compression
npm install express-mongo-sanitize
npm install jsonwebtoken bcryptjs
npm install joi celebrate

# 4. Install development dependencies
npm install -D nodemon

# 5. Buat struktur folder
mkdir -p src/{config,middleware,routes,controllers,utils}

A. Environment Variables Configuration

.env.example

env
# ====================================
# 🚀 APPLICATION CONFIGURATION
# ====================================

# Node Environment
NODE_ENV=development
PORT=3000
APP_NAME=Secure Express API
APP_URL=http://localhost:3000
API_VERSION=v1

# ====================================
# 🔐 SECURITY CONFIGURATION
# ====================================

# JWT Configuration
JWT_SECRET=your-super-secret-jwt-key-min-32-chars-here
JWT_REFRESH_SECRET=your-super-secret-refresh-key-min-32-chars-here
JWT_EXPIRES_IN=15m
JWT_REFRESH_EXPIRES_IN=7d
JWT_ISSUER=secure-api
JWT_AUDIENCE=secure-api-client

# Password Configuration
BCRYPT_SALT_ROUNDS=12
PASSWORD_MIN_LENGTH=8
PASSWORD_MAX_LENGTH=128

# ====================================
# 🗄️ DATABASE CONFIGURATION
# ====================================

# MongoDB (example)
DB_HOST=localhost
DB_PORT=27017
DB_NAME=secure_api
DB_USER=admin
DB_PASSWORD=your-secure-db-password
DB_SSL=true

# ====================================
# 🌐 CORS CONFIGURATION
# ====================================

# Allowed origins (comma-separated)
CORS_ORIGIN=http://localhost:3000,http://localhost:5173,https://yourdomain.com
CORS_CREDENTIALS=true
CORS_MAX_AGE=86400

# ====================================
# ⏱️ RATE LIMITING CONFIGURATION
# ====================================

RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100
RATE_LIMIT_MESSAGE=Too many requests, please try again later

AUTH_RATE_LIMIT_WINDOW_MS=900000
AUTH_RATE_LIMIT_MAX_REQUESTS=5

# ====================================
# 📧 EMAIL CONFIGURATION
# ====================================

SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password

# ====================================
# ☁️ CLOUD STORAGE (AWS S3 example)
# ====================================

AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_REGION=ap-southeast-1
AWS_BUCKET_NAME=your-bucket-name

# ====================================
# 📝 LOGGING CONFIGURATION
# ====================================

LOG_LEVEL=info
LOG_FILE_PATH=logs/app.log
LOG_MAX_SIZE=20m
LOG_MAX_FILES=14d

# ====================================
# 🚨 ALERT CONFIGURATION
# ====================================

SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxx/yyy/zzz
ADMIN_EMAIL=admin@yourdomain.com

.env (Jangan commit ke git!)

env
NODE_ENV=development
PORT=3000
APP_NAME=Secure Express API

# Ganti dengan secret yang kuat!
JWT_SECRET=8f7a9d3e1b5c6a7d8e9f0a1b2c3d4e5f6a7b8c9d
JWT_REFRESH_SECRET=e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4
BCRYPT_SALT_ROUNDS=12

CORS_ORIGIN=http://localhost:3000,http://localhost:5173

.gitignore

gitignore
# Environment variables
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# Dependencies
node_modules/

# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Coverage
coverage
.nyc_output

# Build
dist
build

# IDE
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# AWS
.aws

# Secrets
*.pem
*.key
*.crt

B. Security Configuration Module

src/config/security.js

javascript
/**
 * SECURITY CONFIGURATION
 * Semua konfigurasi keamanan dalam satu tempat
 */

const crypto = require('crypto');

module.exports = {
  // ====================================
  // 🛡️ HELMET CONFIGURATION
  // ====================================
  helmet: {
    contentSecurityPolicy: {
      directives: {
        defaultSrc: ["'self'"],
        styleSrc: ["'self'", "'unsafe-inline'"],
        scriptSrc: ["'self'"],
        imgSrc: ["'self'", "data:", "https:"],
        connectSrc: ["'self'", process.env.APP_URL],
        fontSrc: ["'self'", "https:", "data:"],
        objectSrc: ["'none'"],
        mediaSrc: ["'self'"],
        frameSrc: ["'none'"],
        sandbox: ['allow-forms', 'allow-scripts', 'allow-same-origin'],
        reportUri: '/api/v1/security/csp-violation',
        upgradeInsecureRequests: process.env.NODE_ENV === 'production' ? [] : null
      }
    },
    hsts: {
      maxAge: 31536000, // 1 year
      includeSubDomains: true,
      preload: true
    },
    referrerPolicy: {
      policy: 'strict-origin-when-cross-origin'
    },
    noSniff: true,
    xssFilter: true,
    hidePoweredBy: true,
    frameguard: {
      action: 'deny'
    },
    dnsPrefetchControl: {
      allow: false
    },
    ieNoOpen: true,
    permittedCrossDomainPolicies: {
      permittedPolicies: 'none'
    }
  },

  // ====================================
  // 🌐 CORS CONFIGURATION
  // ====================================
  cors: {
    origin: (origin, callback) => {
      const whitelist = process.env.CORS_ORIGIN?.split(',') || [];
      
      // Allow requests with no origin (like mobile apps, curl, Postman)
      if (!origin || whitelist.includes(origin) || process.env.NODE_ENV !== 'production') {
        callback(null, true);
      } else {
        callback(new Error('CORS policy violation'), false);
      }
    },
    credentials: true,
    methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
    allowedHeaders: [
      'Content-Type',
      'Authorization',
      'X-Request-ID',
      'X-API-Key',
      'X-CSRF-Token',
      'Accept',
      'Origin',
      'Cache-Control'
    ],
    exposedHeaders: [
      'X-RateLimit-Limit',
      'X-RateLimit-Remaining',
      'X-RateLimit-Reset',
      'X-Request-ID'
    ],
    maxAge: parseInt(process.env.CORS_MAX_AGE) || 86400,
    preflightContinue: false,
    optionsSuccessStatus: 204
  },

  // ====================================
  // ⏱️ RATE LIMITING CONFIGURATION
  // ====================================
  rateLimit: {
    // General API rate limit
    api: {
      windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS) || 15 * 60 * 1000, // 15 minutes
      max: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS) || 100,
      message: {
        success: false,
        error: {
          code: 'RATE_LIMIT_EXCEEDED',
          message: process.env.RATE_LIMIT_MESSAGE || 'Too many requests, please try again later',
          retryAfter: '15 minutes'
        }
      },
      standardHeaders: true,
      legacyHeaders: false,
      skipSuccessfulRequests: false,
      keyGenerator: (req) => {
        // Use user ID if authenticated, otherwise IP
        return req.user?.id || req.ip;
      },
      handler: (req, res) => {
        res.status(429).json({
          success: false,
          error: {
            code: 'RATE_LIMIT_EXCEEDED',
            message: 'Too many requests, please try again later',
            retryAfter: Math.ceil(req.rateLimit.resetTime / 1000),
            limit: req.rateLimit.limit,
            remaining: req.rateLimit.remaining
          }
        });
      },
      skip: (req) => {
        // Skip rate limiting for health checks
        return req.path === '/health' || req.path === '/ready';
      }
    },

    // Strict rate limit for authentication endpoints
    auth: {
      windowMs: 15 * 60 * 1000, // 15 minutes
      max: 5, // 5 attempts
      skipSuccessfulRequests: true, // Only count failed attempts
      message: {
        success: false,
        error: {
          code: 'AUTH_RATE_LIMIT_EXCEEDED',
          message: 'Too many authentication attempts. Please try again later.',
          retryAfter: '15 minutes'
        }
      }
    },

    // Very strict for password reset
    passwordReset: {
      windowMs: 60 * 60 * 1000, // 1 hour
      max: 3, // 3 attempts
      message: {
        success: false,
        error: {
          code: 'PASSWORD_RESET_LIMIT_EXCEEDED',
          message: 'Too many password reset attempts. Please try again in 1 hour.',
          retryAfter: '1 hour'
        }
      }
    },

    // Strict for registration
    registration: {
      windowMs: 60 * 60 * 1000, // 1 hour
      max: 5, // 5 registrations per IP per hour
      keyGenerator: (req) => req.ip,
      message: {
        success: false,
        error: {
          code: 'REGISTRATION_LIMIT_EXCEEDED',
          message: 'Too many registration attempts from your IP. Please try again later.',
          retryAfter: '1 hour'
        }
      }
    }
  },

  // ====================================
  // 🔐 JWT CONFIGURATION
  // ====================================
  jwt: {
    access: {
      secret: process.env.JWT_SECRET,
      expiresIn: process.env.JWT_EXPIRES_IN || '15m',
      algorithm: 'HS256',
      issuer: process.env.JWT_ISSUER || 'secure-api',
      audience: process.env.JWT_AUDIENCE || 'secure-api-client'
    },
    refresh: {
      secret: process.env.JWT_REFRESH_SECRET,
      expiresIn: process.env.JWT_REFRESH_EXPIRES_IN || '7d',
      algorithm: 'HS256',
      issuer: process.env.JWT_ISSUER || 'secure-api',
      audience: process.env.JWT_AUDIENCE || 'secure-api-client'
    }
  },

  // ====================================
  // 🔑 PASSWORD CONFIGURATION
  // ====================================
  password: {
    minLength: parseInt(process.env.PASSWORD_MIN_LENGTH) || 8,
    maxLength: parseInt(process.env.PASSWORD_MAX_LENGTH) || 128,
    saltRounds: parseInt(process.env.BCRYPT_SALT_ROUNDS) || 12,
    requirements: {
      uppercase: true,
      lowercase: true,
      numbers: true,
      special: true
    },
    specialChars: '!@#$%^&*()_+-=[]{};\':",./<>?',
    passwordHistory: 5, // Remember last 5 passwords
    expiryDays: 90 // Password expires after 90 days
  },

  // ====================================
  // 🍪 COOKIE CONFIGURATION
  // ====================================
  cookie: {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'strict',
    maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
    domain: process.env.COOKIE_DOMAIN || undefined,
    path: '/',
    signed: true // Sign cookies to prevent tampering
  },

  // ====================================
  // 🧹 INPUT SANITIZATION
  // ====================================
  sanitization: {
    // Allowlisted HTML tags (for rich text)
    allowedHtmlTags: [
      'b', 'i', 'em', 'strong', 'p', 'br', 'ul', 'ol', 'li',
      'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote'
    ],
    // Allowlisted HTML attributes
    allowedHtmlAttributes: ['href', 'title', 'target'],
    // Maximum length for text fields
    maxStringLength: 5000,
    // Maximum depth for nested objects
    maxDepth: 10
  },

  // ====================================
  // 🚨 SECURITY ALERTS
  // ====================================
  alerts: {
    slackWebhook: process.env.SLACK_WEBHOOK_URL,
    adminEmail: process.env.ADMIN_EMAIL,
    thresholds: {
      failedLogins: 10, // Alert after 10 failed logins
      serverErrors: 50, // Alert after 50 server errors in 1 hour
      rateLimitViolations: 100 // Alert after 100 rate limit violations
    }
  }
};

C. Security Middleware Suite

src/middleware/security.middleware.js

javascript
/**
 * SECURITY MIDDLEWARE SUITE
 * Semua middleware keamanan dalam satu file
 */

const helmet = require('helmet');
const cors = require('cors');
const rateLimit = require('express-rate-limit');
const slowDown = require('express-slow-down');
const xss = require('xss-clean');
const hpp = require('hpp');
const mongoSanitize = require('express-mongo-sanitize');
const csrf = require('csurf');
const compression = require('compression');
const crypto = require('crypto');
const config = require('../config/security');
const logger = require('../utils/logger');

class SecurityMiddleware {
  /**
   * ============= 1. HELMET (SECURITY HEADERS) =============
   * Melindungi dari XSS, clickjacking, MIME sniffing, dll
   */
  helmet() {
    return helmet(config.helmet);
  }

  /**
   * ============= 2. CORS (CROSS-ORIGIN RESOURCE SHARING) =============
   * Mengontrol domain mana yang bisa mengakses API
   */
  cors() {
    return cors(config.cors);
  }

  /**
   * ============= 3. RATE LIMITING =============
   * Mencegah brute force dan DDoS attacks
   */
  rateLimiter(type = 'api') {
    return rateLimit(config.rateLimit[type]);
  }

  /**
   * ============= 4. SLOW DOWN =============
   * Perlahan-lahan memperlambat request setelah batas tertentu
   */
  slowDown() {
    return slowDown({
      windowMs: 15 * 60 * 1000, // 15 minutes
      delayAfter: 50, // Allow 50 requests without delay
      delayMs: (hits) => hits * 100, // Add 100ms delay per hit above limit
      maxDelayMs: 10000, // Max 10 second delay
      skip: (req) => req.user?.role === 'admin'
    });
  }

  /**
   * ============= 5. XSS CLEAN =============
   * Membersihkan input dari XSS attacks
   */
  xssClean() {
    return xss();
  }

  /**
   * ============= 6. HPP (HTTP PARAMETER POLLUTION) =============
   * Mencegah parameter pollution attack
   */
  hpp() {
    return hpp();
  }

  /**
   * ============= 7. NoSQL INJECTION PREVENTION =============
   * Membersihkan input dari NoSQL injection
   */
  mongoSanitize() {
    return mongoSanitize({
      replaceWith: '_',
      allowDots: true,
      onSanitize: ({ req, key }) => {
        logger.warn('NoSQL injection attempt detected', {
          ip: req.ip,
          path: req.path,
          key
        });
      }
    });
  }

  /**
   * ============= 8. CSRF PROTECTION =============
   * Mencegah Cross-Site Request Forgery
   */
  csrfProtection() {
    return csrf({
      cookie: {
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production',
        sameSite: 'strict',
        key: '_csrf'
      }
    });
  }

  /**
   * ============= 9. COMPRESSION =============
   * Kompres response untuk performa
   */
  compression() {
    return compression({
      filter: (req, res) => {
        if (req.headers['x-no-compression']) {
          return false;
        }
        return compression.filter(req, res);
      },
      level: 6 // Compression level (1-9)
    });
  }

  /**
   * ============= 10. REQUEST ID =============
   * Generate unique ID untuk setiap request (tracing)
   */
  requestId() {
    return (req, res, next) => {
      req.id = req.headers['x-request-id'] || 
               `req-${crypto.randomBytes(16).toString('hex')}`;
      res.setHeader('X-Request-ID', req.id);
      next();
    };
  }

  /**
   * ============= 11. CSP VIOLATION HANDLER =============
   * Menangani laporan CSP violation
   */
  cspViolationHandler() {
    return (req, res) => {
      const report = req.body;
      
      logger.warn('CSP Violation', {
        'document-uri': report['csp-report']?.['document-uri'],
        'blocked-uri': report['csp-report']?.['blocked-uri'],
        'violated-directive': report['csp-report']?.['violated-directive'],
        'original-policy': report['csp-report']?.['original-policy'],
        ip: req.ip,
        userAgent: req.headers['user-agent']
      });

      res.status(204).end();
    };
  }

  /**
   * ============= 12. SSL REDIRECT =============
   * Redirect HTTP ke HTTPS di production
   */
  sslRedirect() {
    return (req, res, next) => {
      if (process.env.NODE_ENV === 'production' && !req.secure) {
        return res.redirect(`https://${req.headers.host}${req.url}`);
      }
      next();
    };
  }

  /**
   * ============= 13. HIDE SENSITIVE HEADERS =============
   * Hapus header yang tidak perlu
   */
  hideSensitiveHeaders() {
    return (req, res, next) => {
      res.removeHeader('X-Powered-By');
      res.removeHeader('Server');
      res.removeHeader('X-AspNet-Version');
      res.removeHeader('X-AspNetMvc-Version');
      next();
    };
  }

  /**
   * ============= 14. JSON PARSER WITH SIZE LIMIT =============
   * Batasi ukuran request body
   */
  jsonParser() {
    return (req, res, next) => {
      express.json({ 
        limit: '10mb',
        verify: (req, res, buf) => {
          try {
            JSON.parse(buf);
          } catch (e) {
            res.status(400).json({
              success: false,
              error: {
                code: 'INVALID_JSON',
                message: 'Invalid JSON payload'
              }
            });
            throw new Error('Invalid JSON');
          }
        }
      })(req, res, next);
    };
  }

  /**
   * ============= 15. URL ENCODED PARSER =============
   * Parse URL-encoded bodies dengan size limit
   */
  urlEncodedParser() {
    return express.urlencoded({ 
      extended: true, 
      limit: '10mb' 
    });
  }

  /**
   * ============= 16. API KEY AUTHENTICATION =============
   * Validasi API key untuk service-to-service communication
   */
  apiKeyAuth() {
    return (req, res, next) => {
      const apiKey = req.headers['x-api-key'];
      const validApiKeys = process.env.API_KEYS?.split(',') || [];

      // Skip untuk internal routes
      if (req.path.startsWith('/internal')) {
        if (!apiKey || !validApiKeys.includes(apiKey)) {
          logger.warn('Invalid API key attempt', {
            ip: req.ip,
            path: req.path,
            apiKey: apiKey?.substring(0, 8)
          });

          return res.status(401).json({
            success: false,
            error: {
              code: 'INVALID_API_KEY',
              message: 'Invalid API key'
            }
          });
        }
      }

      next();
    };
  }

  /**
   * ============= 17. CONTENT SECURITY POLICY LOGGER =============
   * Log CSP violations untuk monitoring
   */
  static logCspViolation(req, res, next) {
    res.on('finish', () => {
      if (res.statusCode === 403 && res.getHeader('X-CSP-Violation')) {
        logger.warn('CSP violation blocked', {
          url: req.url,
          ip: req.ip,
          userAgent: req.headers['user-agent']
        });
      }
    });
    next();
  }

  /**
   * ============= 18. SECURE COOKIE SETTER =============
   * Set cookie dengan konfigurasi aman
   */
  static setSecureCookie(res, name, value, options = {}) {
    const defaultOptions = {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      sameSite: 'strict',
      path: '/',
      maxAge: 7 * 24 * 60 * 60 * 1000,
      signed: true
    };

    res.cookie(name, value, { ...defaultOptions, ...options });
  }

  /**
   * ============= 19. SECURITY AUDIT LOGGER =============
   * Log semua event keamanan penting
   */
  static logSecurityEvent(event, req, details = {}) {
    const logData = {
      event,
      timestamp: new Date().toISOString(),
      ip: req.ip,
      userAgent: req.headers['user-agent'],
      userId: req.user?.id,
      email: req.user?.email,
      path: req.path,
      method: req.method,
      requestId: req.id,
      ...details
    };

    // Log ke file khusus security
    logger.security(logData);

    // Kirim alert untuk event kritis
    if (event.includes('FAILED') || event.includes('VIOLATION')) {
      this.sendSecurityAlert(event, logData);
    }
  }

  /**
   * ============= 20. SECURITY ALERT SENDER =============
   * Kirim alert ke Slack/Email untuk event kritis
   */
  static async sendSecurityAlert(event, data) {
    // Skip di development
    if (process.env.NODE_ENV === 'development') return;

    // Send to Slack
    if (process.env.SLACK_WEBHOOK_URL) {
      try {
        await fetch(process.env.SLACK_WEBHOOK_URL, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            text: `🚨 *Security Alert: ${event}*\n`,
            attachments: [{
              color: 'danger',
              fields: Object.entries(data).map(([key, value]) => ({
                title: key,
                value: String(value),
                short: true
              }))
            }]
          })
        });
      } catch (error) {
        logger.error('Failed to send Slack alert', error);
      }
    }
  }
}

module.exports = new SecurityMiddleware();

D. Environment Variable Validator

src/config/envValidator.js

javascript
/**
 * ENVIRONMENT VARIABLE VALIDATOR
 * Validasi semua env variable saat startup
 */

const logger = require('../utils/logger');

class EnvValidator {
  constructor() {
    this.errors = [];
    this.warnings = [];
  }

  /**
   * Validasi semua environment variables
   */
  validate() {
    this.validateNodeEnv();
    this.validateJwtSecrets();
    this.validateDatabaseConfig();
    this.validateCorsConfig();
    this.validateRateLimits();

    if (this.errors.length > 0) {
      logger.error('❌ Environment validation failed!');
      this.errors.forEach(error => logger.error(`${error}`));
      throw new Error('Environment validation failed');
    }

    if (this.warnings.length > 0) {
      logger.warn('⚠️  Environment warnings:');
      this.warnings.forEach(warning => logger.warn(`${warning}`));
    }

    logger.info('✅ Environment validation passed');
    return true;
  }

  /**
   * Validasi NODE_ENV
   */
  validateNodeEnv() {
    const validEnvs = ['development', 'test', 'production'];
    if (!process.env.NODE_ENV) {
      process.env.NODE_ENV = 'development';
      this.warnings.push('NODE_ENV not set, defaulting to "development"');
    } else if (!validEnvs.includes(process.env.NODE_ENV)) {
      this.errors.push(`NODE_ENV must be one of: ${validEnvs.join(', ')}`);
    }
  }

  /**
   * Validasi JWT secrets
   */
  validateJwtSecrets() {
    // JWT Secret
    if (!process.env.JWT_SECRET) {
      this.errors.push('JWT_SECRET is required');
    } else if (process.env.JWT_SECRET.length < 32) {
      this.errors.push('JWT_SECRET must be at least 32 characters long');
    }

    // JWT Refresh Secret
    if (!process.env.JWT_REFRESH_SECRET) {
      if (process.env.NODE_ENV === 'production') {
        this.errors.push('JWT_REFRESH_SECRET is required in production');
      } else {
        process.env.JWT_REFRESH_SECRET = process.env.JWT_SECRET;
        this.warnings.push('JWT_REFRESH_SECRET not set, using JWT_SECRET (development only)');
      }
    }

    // JWT Expiration
    if (!process.env.JWT_EXPIRES_IN) {
      process.env.JWT_EXPIRES_IN = '15m';
      this.warnings.push('JWT_EXPIRES_IN not set, defaulting to "15m"');
    }

    if (!process.env.JWT_REFRESH_EXPIRES_IN) {
      process.env.JWT_REFRESH_EXPIRES_IN = '7d';
      this.warnings.push('JWT_REFRESH_EXPIRES_IN not set, defaulting to "7d"');
    }
  }

  /**
   * Validasi database configuration
   */
  validateDatabaseConfig() {
    // Skip if no DB config (might be file-based)
    if (!process.env.DB_HOST && !process.env.DATABASE_URL) {
      this.warnings.push('No database configuration found');
      return;
    }

    // Database URL
    if (process.env.DATABASE_URL) {
      if (!process.env.DATABASE_URL.startsWith('postgresql://') && 
          !process.env.DATABASE_URL.startsWith('mongodb://') &&
          !process.env.DATABASE_URL.startsWith('mysql://')) {
        this.warnings.push('DATABASE_URL format may be invalid');
      }
      return;
    }

    // Individual DB config
    if (!process.env.DB_HOST) {
      this.errors.push('DB_HOST is required when using individual DB config');
    }

    if (!process.env.DB_NAME) {
      this.errors.push('DB_NAME is required when using individual DB config');
    }

    if (!process.env.DB_USER) {
      this.warnings.push('DB_USER not set, may cause issues');
    }

    if (!process.env.DB_PASSWORD && process.env.NODE_ENV === 'production') {
      this.errors.push('DB_PASSWORD is required in production');
    }
  }

  /**
   * Validasi CORS configuration
   */
  validateCorsConfig() {
    if (!process.env.CORS_ORIGIN) {
      if (process.env.NODE_ENV === 'production') {
        this.errors.push('CORS_ORIGIN is required in production');
      } else {
        process.env.CORS_ORIGIN = 'http://localhost:3000';
        this.warnings.push('CORS_ORIGIN not set, defaulting to "http://localhost:3000"');
      }
    }

    // Validate CORS origins format
    if (process.env.CORS_ORIGIN) {
      const origins = process.env.CORS_ORIGIN.split(',');
      origins.forEach(origin => {
        origin = origin.trim();
        if (origin !== '*' && !origin.startsWith('http://') && !origin.startsWith('https://')) {
          this.warnings.push(`CORS origin "${origin}" should start with http:// or https://`);
        }
      });
    }
  }

  /**
   * Validasi rate limiting
   */
  validateRateLimits() {
    if (!process.env.RATE_LIMIT_MAX_REQUESTS) {
      process.env.RATE_LIMIT_MAX_REQUESTS = '100';
      this.warnings.push('RATE_LIMIT_MAX_REQUESTS not set, defaulting to 100');
    }

    const maxRequests = parseInt(process.env.RATE_LIMIT_MAX_REQUESTS);
    if (isNaN(maxRequests) || maxRequests < 1) {
      this.errors.push('RATE_LIMIT_MAX_REQUESTS must be a positive number');
    }

    if (!process.env.RATE_LIMIT_WINDOW_MS) {
      process.env.RATE_LIMIT_WINDOW_MS = '900000'; // 15 minutes
      this.warnings.push('RATE_LIMIT_WINDOW_MS not set, defaulting to 15 minutes');
    }
  }

  /**
   * Validasi bcrypt salt rounds
   */
  validateBcryptSaltRounds() {
    if (!process.env.BCRYPT_SALT_ROUNDS) {
      process.env.BCRYPT_SALT_ROUNDS = '12';
      this.warnings.push('BCRYPT_SALT_ROUNDS not set, defaulting to 12');
    }

    const saltRounds = parseInt(process.env.BCRYPT_SALT_ROUNDS);
    if (isNaN(saltRounds) || saltRounds < 10 || saltRounds > 20) {
      this.warnings.push('BCRYPT_SALT_ROUNDS should be between 10 and 20');
    }
  }

  /**
   * Validasi port
   */
  validatePort() {
    if (!process.env.PORT) {
      process.env.PORT = '3000';
      this.warnings.push('PORT not set, defaulting to 3000');
    }

    const port = parseInt(process.env.PORT);
    if (isNaN(port) || port < 1 || port > 65535) {
      this.errors.push('PORT must be a valid port number (1-65535)');
    }
  }
}

module.exports = new EnvValidator();

E. Complete Secure Express Application

src/app.js

javascript
/**
 * SECURE EXPRESS APPLICATION
 * Enterprise-grade security configuration
 */

const express = require('express');
const cookieParser = require('cookie-parser');
const path = require('path');

// Security middleware
const securityMiddleware = require('./middleware/security.middleware');
const envValidator = require('./config/envValidator');
const config = require('./config/security');
const logger = require('./utils/logger');

// Load environment variables
require('dotenv').config();

// Validate environment variables
envValidator.validate();

const app = express();

// ====================================
// 🎯 GLOBAL MIDDLEWARE - ORDER IS CRITICAL!
// ====================================

// 1. Request ID (must be first for tracing)
app.use(securityMiddleware.requestId());

// 2. SSL Redirect (production only)
if (process.env.NODE_ENV === 'production') {
  app.use(securityMiddleware.sslRedirect());
}

// 3. Security Headers
app.use(securityMiddleware.helmet());

// 4. CORS
app.use(securityMiddleware.cors());

// 5. Compression
app.use(securityMiddleware.compression());

// 6. Rate Limiting (apply early)
app.use('/api', securityMiddleware.rateLimiter('api'));
app.use('/api/auth', securityMiddleware.rateLimiter('auth'));
app.use('/api/auth/forgot-password', securityMiddleware.rateLimiter('passwordReset'));
app.use('/api/auth/register', securityMiddleware.rateLimiter('registration'));

// 7. Slow Down (gradual throttling)
app.use(securityMiddleware.slowDown());

// 8. Body Parsers with size limits
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
app.use(cookieParser(process.env.JWT_SECRET));

// 9. API Key Authentication (for internal services)
app.use(securityMiddleware.apiKeyAuth());

// 10. Security sanitization
app.use(securityMiddleware.xssClean());
app.use(securityMiddleware.hpp());
app.use(securityMiddleware.mongoSanitize());

// 11. Remove sensitive headers
app.use(securityMiddleware.hideSensitiveHeaders());

// 12. CSP Violation endpoint
app.post('/api/v1/security/csp-violation', 
  express.json({ type: 'application/csp-report' }),
  securityMiddleware.cspViolationHandler()
);

// ====================================
// 📊 HEALTH CHECKS
// ====================================

// Public health check (no rate limit)
app.get('/health', (req, res) => {
  res.json({
    status: 'healthy',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    environment: process.env.NODE_ENV,
    version: process.env.npm_package_version || '1.0.0',
    requestId: req.id
  });
});

// Readiness probe (for Kubernetes)
app.get('/ready', (req, res) => {
  // Check database connection, etc.
  const isReady = true; // Implement actual checks
  
  if (isReady) {
    res.json({ status: 'ready', requestId: req.id });
  } else {
    res.status(503).json({ status: 'not ready', requestId: req.id });
  }
});

// ====================================
// 🚀 API ROUTES
// ====================================

app.use('/api/v1', require('./routes'));

// ====================================
// 📁 STATIC FILES (if needed)
// ====================================

if (process.env.NODE_ENV === 'production') {
  app.use(express.static(path.join(__dirname, '../public')));
  
  app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname, '../public/index.html'));
  });
}

// ====================================
// 🚨 404 HANDLER
// ====================================

app.use((req, res) => {
  logger.warn('404 Not Found', {
    requestId: req.id,
    method: req.method,
    url: req.originalUrl,
    ip: req.ip
  });

  res.status(404).json({
    success: false,
    error: {
      code: 'NOT_FOUND',
      message: `Cannot ${req.method} ${req.originalUrl}`,
      requestId: req.id
    }
  });
});

// ====================================
// 🔥 GLOBAL ERROR HANDLER
// ====================================

app.use((err, req, res, next) => {
  // Log error
  logger.error('Unhandled error:', {
    requestId: req.id,
    error: err.message,
    stack: err.stack,
    code: err.code,
    statusCode: err.statusCode || 500
  });

  // Security: Don't expose error details in production
  const isProduction = process.env.NODE_ENV === 'production';
  
  res.status(err.statusCode || 500).json({
    success: false,
    error: {
      code: err.code || 'INTERNAL_SERVER_ERROR',
      message: isProduction ? 'Internal server error' : err.message,
      requestId: req.id,
      ...(isProduction ? {} : { stack: err.stack })
    }
  });
});

// ====================================
// 🛡️ SECURITY AUDIT LOGGING
// ====================================

// Log all requests in production
if (process.env.NODE_ENV === 'production') {
  app.use((req, res, next) => {
    res.on('finish', () => {
      if (res.statusCode >= 400) {
        securityMiddleware.logSecurityEvent('HTTP_ERROR', req, {
          statusCode: res.statusCode,
          responseTime: res.getHeader('X-Response-Time')
        });
      }
    });
    next();
  });
}

module.exports = app;

F. CSRF Protection Implementation

src/middleware/csrf.middleware.js

javascript
/**
 * CSRF PROTECTION MIDDLEWARE
 * Mencegah Cross-Site Request Forgery attacks
 */

const csrf = require('csurf');
const { ValidationError } = require('../errors/AppError');
const logger = require('../utils/logger');

class CsrfMiddleware {
  constructor() {
    this.protection = csrf({
      cookie: {
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production',
        sameSite: 'strict',
        key: '_csrf',
        maxAge: 3600 // 1 hour
      },
      value: (req) => {
        // Check in header first, then body
        return req.headers['x-csrf-token'] || 
               req.headers['xsrf-token'] || 
               req.body._csrf;
      }
    });
  }

  /**
   * CSRF Protection middleware
   */
  protect() {
    return (req, res, next) => {
      // Skip CSRF for GET, HEAD, OPTIONS
      if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) {
        return next();
      }

      // Skip CSRF for API routes that use JWT
      if (req.path.startsWith('/api/') && req.headers.authorization) {
        return next();
      }

      this.protection(req, res, (err) => {
        if (err) {
          logger.warn('CSRF attack detected', {
            requestId: req.id,
            ip: req.ip,
            path: req.path,
            method: req.method,
            userId: req.user?.id
          });

          return next(new ValidationError('Invalid CSRF token', [
            { field: '_csrf', message: 'CSRF token is invalid or missing' }
          ]));
        }
        next();
      });
    };
  }

  /**
   * Generate CSRF token
   */
  generateToken(req, res) {
    return {
      _csrf: req.csrfToken()
    };
  }

  /**
   * CSRF Error handler
   */
  errorHandler(err, req, res, next) {
    if (err.code === 'EBADCSRFTOKEN') {
      return res.status(403).json({
        success: false,
        error: {
          code: 'INVALID_CSRF_TOKEN',
          message: 'Invalid CSRF token',
          requestId: req.id
        }
      });
    }
    next(err);
  }
}

module.exports = new CsrfMiddleware();

G. Input Validation & Sanitization

src/utils/sanitizer.js

javascript
/**
 * INPUT SANITIZATION UTILITY
 * Membersihkan input dari karakter berbahaya
 */

const sanitizeHtml = require('sanitize-html');

class Sanitizer {
  /**
   * Sanitize string untuk mencegah XSS
   */
  static xss(input) {
    if (typeof input !== 'string') return input;

    return sanitizeHtml(input, {
      allowedTags: [], // No HTML tags allowed
      allowedAttributes: {},
      disallowedTagsMode: 'discard',
      textFilter: (text) => {
        // Escape any remaining HTML entities
        return text
          .replace(/&/g, '&amp;')
          .replace(/</g, '&lt;')
          .replace(/>/g, '&gt;')
          .replace(/"/g, '&quot;')
          .replace(/'/g, '&#x27;')
          .replace(/\//g, '&#x2F;');
      }
    });
  }

  /**
   * Sanitize object recursively
   */
  static deepSanitize(obj) {
    if (!obj || typeof obj !== 'object') {
      return this.xss(obj);
    }

    if (Array.isArray(obj)) {
      return obj.map(item => this.deepSanitize(item));
    }

    const sanitized = {};
    for (const [key, value] of Object.entries(obj)) {
      sanitized[key] = this.deepSanitize(value);
    }
    return sanitized;
  }

  /**
   * Sanitize email
   */
  static email(email) {
    if (typeof email !== 'string') return '';
    
    return email
      .trim()
      .toLowerCase()
      .replace(/\s+/g, '')
      .replace(/[<>()\[\]\\,;:%#^$@!~&*?]/g, ''); // Remove dangerous chars
  }

  /**
   * Sanitize phone number
   */
  static phone(phone) {
    if (typeof phone !== 'string') return '';
    
    // Remove all non-digit characters except +
    return phone.replace(/[^\d+]/g, '');
  }

  /**
   * Sanitize URL
   */
  static url(url) {
    if (typeof url !== 'string') return '';
    
    try {
      const parsed = new URL(url);
      // Only allow HTTP and HTTPS
      if (!['http:', 'https:'].includes(parsed.protocol)) {
        return '';
      }
      return parsed.toString();
    } catch {
      return '';
    }
  }

  /**
   * Sanitize filename
   */
  static filename(filename) {
    if (typeof filename !== 'string') return '';
    
    // Remove path traversal attempts
    let clean = filename.replace(/\.\./g, '')
                        .replace(/[/\\]/g, '');
    
    // Remove non-printable characters
    clean = clean.replace(/[\x00-\x1f\x80-\x9f]/g, '');
    
    // Limit length
    return clean.slice(0, 255);
  }

  /**
   * Sanitize SQL input (basic)
   */
  static sql(input) {
    if (typeof input !== 'string') return input;
    
    // Remove SQL keywords (case insensitive)
    const sqlKeywords = [
      'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'DROP', 'UNION',
      'ALTER', 'CREATE', 'WHERE', 'FROM', 'JOIN', '--', ';'
    ];
    
    let sanitized = input;
    sqlKeywords.forEach(keyword => {
      const regex = new RegExp(keyword, 'gi');
      sanitized = sanitized.replace(regex, '');
    });
    
    return sanitized;
  }

  /**
   * Sanitize MongoDB input
   */
  static mongodb(input) {
    if (typeof input === 'object') {
      // Remove MongoDB operators
      const sanitized = {};
      for (const [key, value] of Object.entries(input)) {
        if (!key.startsWith('$')) {
          sanitized[key] = value;
        }
      }
      return sanitized;
    }
    return input;
  }
}

module.exports = Sanitizer;

3.3 Security Headers Explanation

javascript
/**
 * SECURITY HEADERS EXPLANATION
 * 
 * ┌─────────────────────────────────────────────────────────────┐
 * │ 1. Content-Security-Policy (CSP)                          │
 * ├─────────────────────────────────────────────────────────────┤
 * │ Apa: Browser directive untuk sumber daya yang diizinkan    │
 * │ Cegah: XSS, data injection, clickjacking                  │
 * │ Contoh: default-src 'self'; script-src 'self';            │
 * └─────────────────────────────────────────────────────────────┘
 * 
 * ┌─────────────────────────────────────────────────────────────┐
 * │ 2. Strict-Transport-Security (HSTS)                       │
 * ├─────────────────────────────────────────────────────────────┤
 * │ Apa: Memaksa browser selalu menggunakan HTTPS              │
 * │ Cegah: SSL stripping, man-in-the-middle                   │
 * │ Contoh: max-age=31536000; includeSubDomains               │
 * └─────────────────────────────────────────────────────────────┘
 * 
 * ┌─────────────────────────────────────────────────────────────┐
 * │ 3. X-Frame-Options                                        │
 * ├─────────────────────────────────────────────────────────────┤
 * │ Apa: Mencegah website di-frame oleh situs lain            │
 * │ Cegah: Clickjacking attacks                               │
 * │ Contoh: DENY nebo SAMEORIGIN                              │
 * └─────────────────────────────────────────────────────────────┘
 * 
 * ┌─────────────────────────────────────────────────────────────┐
 * │ 4. X-Content-Type-Options                                 │
 * ├─────────────────────────────────────────────────────────────┤
 * │ Apa: Mencegah browser "menebak" content type              │
 * │ Cegah: MIME sniffing attacks                              │
 * │ Contoh: nosniff                                           │
 * └─────────────────────────────────────────────────────────────┘
 * 
 * ┌─────────────────────────────────────────────────────────────┐
 * │ 5. Referrer-Policy                                        │
 * ├─────────────────────────────────────────────────────────────┤
 * │ Apa: Mengontrol informasi referrer yang dikirim           │
 * │ Cegah: Information leakage                                │
 * │ Contoh: strict-origin-when-cross-origin                   │
 * └─────────────────────────────────────────────────────────────┘
 * 
 * ┌─────────────────────────────────────────────────────────────┐
 * │ 6. Permissions-Policy                                     │
 * ├─────────────────────────────────────────────────────────────┤
 * │ Apa: Mengontrol fitur browser yang bisa digunakan         │
 * │ Cegah: Unwanted access to camera, mic, location           │
 * │ Contoh: geolocation=(self), microphone=()                 │
 * └─────────────────────────────────────────────────────────────┘
 * 
 * ┌─────────────────────────────────────────────────────────────┐
 * │ 7. X-XSS-Protection                                       │
 * ├─────────────────────────────────────────────────────────────┤
 * │ Apa: Mengaktifkan XSS filter di browser                   │
 * │ Cegah: Reflected XSS attacks                              │
 * │ Contoh: 1; mode=block                                     │
 * └─────────────────────────────────────────────────────────────┘
 */

3.4 Common Vulnerabilities & Prevention

javascript
/**
 * COMMON WEB VULNERABILITIES & PREVENTION
 * Berdasarkan OWASP Top 10
 */

const owaspPrevention = {
  /**
   * 1. SQL INJECTION
   * Attack: ' OR '1'='1' --
   * Prevent: Parameterized queries, ORM, input validation
   */
  sqlInjection: {
    vulnerable: `
      // ❌ JANGAN PERNAH LAKUKAN INI!
      const query = \`SELECT * FROM users WHERE email = '${email}'\`;
      db.query(query);
    `,
    secure: `
      // ✅ SELALU GUNAKAN PARAMETERIZED QUERIES
      const query = 'SELECT * FROM users WHERE email = ?';
      db.query(query, [email]);
      
      // Atau gunakan ORM
      User.findOne({ where: { email } });
    `
  },

  /**
   * 2. CROSS-SITE SCRIPTING (XSS)
   * Attack: <script>alert('hacked')</script>
   * Prevent: Escape output, sanitize input, CSP
   */
  xss: {
    vulnerable: `
      // ❌ JANGAN PERNAK LAKUKAN INI!
      res.send(\`<div>${userInput}</div>\`);
    `,
    secure: `
      // ✅ SELALU ESCAPE OUTPUT
      res.send(\`<div>\${escapeHtml(userInput)}</div>\`);
      
      // Atau gunakan template engine yang auto-escape
      res.render('template', { userInput });
      
      // Dan sanitize input
      const clean = xss(input);
    `
  },

  /**
   * 3. CROSS-SITE REQUEST FORGERY (CSRF)
   * Attack: <img src="http://bank.com/transfer?to=hacker&amount=1000000">
   * Prevent: CSRF tokens, SameSite cookies, Double submit
   */
  csrf: {
    vulnerable: `
      // ❌ JANGAN LAKUKAN INI UNTUK STATE-CHANGING OPERATIONS
      app.post('/transfer', (req, res) => {
        // No CSRF protection!
      });
    `,
    secure: `
      // ✅ SELALU GUNAKAN CSRF PROTECTION
      app.use(csrf());
      
      app.post('/transfer', csrfProtection, (req, res) => {
        // Valid CSRF token required
      });
    `
  },

  /**
   * 4. INSECURE DIRECT OBJECT REFERENCES (IDOR)
   * Attack: /api/users/123 -> ubah jadi /api/users/456
   * Prevent: Authorization check, ownership validation
   */
  idor: {
    vulnerable: `
      // ❌ JANGAN LAKUKAN INI!
      app.get('/api/users/:id', (req, res) => {
        const user = User.findById(req.params.id);
        res.json(user); // No authorization check!
      });
    `,
    secure: `
      // ✅ SELALU CEK AUTHORIZATION
      app.get('/api/users/:id', authenticate, (req, res) => {
        const user = User.findById(req.params.id);
        
        // Cek ownership atau role
        if (req.user.id !== user.id && req.user.role !== 'admin') {
          throw new ForbiddenError();
        }
        
        res.json(user);
      });
    `
  },

  /**
   * 5. SECURITY MISCONFIGURATION
   * Attack: Default credentials, verbose errors, outdated software
   * Prevent: Hardening, env variables, security headers
   */
  misconfiguration: {
    vulnerable: `
      // ❌ JANGAN LAKUKAN INI!
      app.use(express.json());
      // No helmet, no rate limiting, no CORS
      // X-Powered-By: Express (exposed!)
      // Stack traces in production!
    `,
    secure: `
      // ✅ SELALU KONFIGURASI DENGAN AMAN
      app.use(helmet());
      app.use(cors({
        origin: whitelist,
        credentials: true
      }));
      app.use(rateLimit({
        windowMs: 15 * 60 * 1000,
        max: 100
      }));
      app.disable('x-powered-by');
      
      // Environment variables untuk secrets
      const secret = process.env.JWT_SECRET;
    `
  },

  /**
   * 6. SENSITIVE DATA EXPOSURE
   * Attack: Steal passwords, credit cards, personal data
   * Prevent: Encryption, HTTPS, no sensitive data in JWT
   */
  sensitiveData: {
    vulnerable: `
      // ❌ JANGAN LAKUKAN INI!
      const user = { 
        id: 1, 
        email: 'user@email.com',
        password: 'plaintext123', // ⚠️
        creditCard: '4111-1111-1111-1111', // ⚠️
        ssn: '123-45-6789' // ⚠️
      };
      
      // Jangan simpan password plaintext!
      // Jangan include di JWT!
    `,
    secure: `
      // ✅ SELALU ENKRIPSI DATA SENSITIF
      const hashedPassword = await bcrypt.hash(password, 12);
      
      // Jangan pernah kirim password ke client
      const { password, ...userWithoutPassword } = user;
      
      // HTTPS di production
      // Encrypt data at rest
    `
  },

  /**
   * 7. INSUFFICIENT LOGGING & MONITORING
   * Attack: Attackers can probe system without detection
   * Prevent: Comprehensive logging, alerts, audit trails
   */
  logging: {
    vulnerable: `
      // ❌ JANGAN LAKUKAN INI!
      app.post('/login', (req, res) => {
        // No logging of failed attempts!
        if (loginSuccessful) {
          res.json({ success: true });
        }
      });
    `,
    secure: `
      // ✅ SELALU LOG EVENT PENTING
      app.post('/login', (req, res) => {
        if (!loginSuccessful) {
          logger.warn('Failed login attempt', {
            email: req.body.email,
            ip: req.ip,
            userAgent: req.headers['user-agent']
          });
          
          // Alert after X attempts
          if (attempts > 5) {
            alertService.send('Multiple failed logins');
          }
        }
      });
    `
  },

  /**
   * 8. DEPENDENCY VULNERABILITIES
   * Attack: Exploit known vulnerabilities in packages
   * Prevent: Regular updates, npm audit, SCA tools
   */
  dependencies: {
    vulnerable: `
      # ❌ JANGAN GUNAKAN VERSI LAMA
      "express": "4.16.0", // Vulnerable version
      
      # Tidak menjalankan npm audit
    `,
    secure: `
      # ✅ SELALU UPDATE DAN AUDIT
      npm update
      npm audit fix
      
      "express": "^4.18.2", // Latest stable
      
      # Use SCA tools: Snyk, Dependabot
    `
  }
};

3.5 Security Testing Tools

javascript
/**
 * SECURITY TESTING TOOLS
 */

const securityTesting = {
  /**
   * 1. STATIC ANALYSIS
   * Scan code for vulnerabilities
   */
  staticAnalysis: [
    'ESLint with security plugins',
    'SonarQube',
    'Snyk Code',
    'GitHub CodeQL',
    'npm audit',
    'yarn audit'
  ],

  /**
   * 2. DYNAMIC ANALYSIS
   * Test running application
   */
  dynamicAnalysis: [
    'OWASP ZAP',
    'Burp Suite',
    'Postman Security Tests',
    'Fiddler',
    'Nikto'
  ],

  /**
   * 3. DEPENDENCY SCANNING
   * Check packages for vulnerabilities
   */
  dependencyScanning: [
    'npm audit',
    'Snyk',
    'Dependabot',
    'Retire.js',
    'OWASP Dependency-Check'
  ],

  /**
   * 4. API SECURITY TESTING
   * Specialized API testing
   */
  apiSecurity: [
    'Postman',
    'Insomnia',
    'SoapUI',
    'RESTler (Microsoft)',
    'APISecurity.io'
  ],

  /**
   * 5. PENETRATION TESTING
   * Manual security assessment
   */
  pentesting: [
    'OWASP Testing Guide',
    'PTES (Penetration Testing Execution Standard)',
    'OSSTMM'
  ],

  /**
   * npm script untuk security testing
   */
  npmScripts: {
    audit: 'npm audit',
    auditFix: 'npm audit fix',
    snyk: 'snyk test',
    snykMonitor: 'snyk monitor',
    zap: 'zap-cli quick-scan --self-contained --ajax-spider --spider http://localhost:3000',
    securityScan: 'npm run audit && npm run snyk',
    securityFix: 'npm run audit-fix && npm update'
  }
};

3.6 Production Security Checklist

javascript
/**
 * PRODUCTION SECURITY CHECKLIST
 * Jalankan sebelum deploy ke production!
 */

const productionChecklist = {
  // ====================================
  // 🔐 ENVIRONMENT & CONFIGURATION
  // ====================================
  environment: [
    '✓ NODE_ENV=production',
    '✓ No hardcoded secrets in code',
    '✓ All secrets in environment variables',
    '✓ JWT_SECRET: min 32 chars, random',
    '✓ Strong password for database',
    '✓ .env in .gitignore',
    '✓ No debug/console.log statements'
  ],

  // ====================================
  // 🛡️ EXPRESS SECURITY
  // ====================================
  express: [
    '✓ Helmet.js configured',
    '✓ CORS whitelist defined',
    '✓ Rate limiting enabled',
    '✓ CSRF protection (for forms)',
    '✓ XSS protection enabled',
    '✓ SQL/NoSQL injection prevention',
    '✓ HPP protection',
    '✓ Compression enabled',
    '✓ Body parser size limits',
    '✓ app.disable("x-powered-by")'
  ],

  // ====================================
  // 🔑 AUTHENTICATION & AUTHORIZATION
  // ====================================
  auth: [
    '✓ Passwords hashed with bcrypt (rounds >= 12)',
    '✓ JWT short expiration (15m-1h)',
    '✓ Refresh tokens implemented',
    '✓ Rate limiting on auth endpoints',
    '✓ Account lockout after failed attempts',
    '✓ Password complexity requirements',
    '✓ Secure password reset flow',
    '✓ 2FA for admin accounts',
    '✓ Session management'
  ],

  // ====================================
  // 🌐 HTTPS & SSL/TLS
  // ====================================
  https: [
    '✓ Valid SSL certificate',
    '✓ Force HTTPS (HSTS)',
    '✓ Secure protocols (TLS 1.2+)',
    '✓ Weak ciphers disabled',
    '✓ Perfect Forward Secrecy',
    '✓ SSL Labs test: A+',
    '✓ HTTP/2 enabled'
  ],

  // ====================================
  // 🗄️ DATABASE SECURITY
  // ====================================
  database: [
    '✓ Database not exposed to internet',
    '✓ Strong credentials',
    '✓ Least privilege principle',
    '✓ Encrypted connections (SSL/TLS)',
    '✓ Regular backups',
    '✓ Encrypted at rest',
    '✓ No SQL injection vulnerabilities'
  ],

  // ====================================
  // 📦 DEPENDENCIES
  // ====================================
  dependencies: [
    '✓ npm audit passed',
    '✓ All dependencies updated',
    '✓ No deprecated packages',
    '✓ No known vulnerabilities',
    '✓ Dependabot/Snyk configured',
    '✓ package-lock.json committed'
  ],

  // ====================================
  // 📝 LOGGING & MONITORING
  // ====================================
  logging: [
    '✓ No sensitive data in logs',
    '✓ Log rotation configured',
    '✓ Centralized logging',
    '✓ Error tracking (Sentry, etc.)',
    '✓ Performance monitoring (APM)',
    '✓ Security event logging',
    '✓ Audit trail for sensitive operations'
  ],

  // ====================================
  // 🚨 ERROR HANDLING
  // ====================================
  errorHandling: [
    '✓ No stack traces in production',
    '✓ Custom error pages',
    '✓ Global error handler',
    '✓ 404 handler',
    '✓ Graceful degradation'
  ],

  // ====================================
  // 📁 FILE UPLOADS
  // ====================================
  fileUploads: [
    '✓ File type validation',
    '✓ File size limits',
    '✓ Scan for malware',
    '✓ Store outside webroot',
    '✓ Random filenames',
    '✓ No execution permissions',
    '✓ Virus scanning',
    '✓ Content-Disposition header'
  ],

  // ====================================
  // 🚀 DEPLOYMENT
  // ====================================
  deployment: [
    '✓ Running as non-root user',
    '✓ Minimal privileges',
    '✓ Firewall configured',
    '✓ SSH key authentication',
    '✓ Fail2ban configured',
    '✓ Regular security updates',
    '✓ Backup & recovery plan',
    '✓ Incident response plan'
  ],

  // ====================================
  // 🧪 PENETRATION TESTING
  // ====================================
  penetrationTesting: [
    '✓ OWASP Top 10 tested',
    '✓ API security tested',
    '✓ Authentication bypass tested',
    '✓ IDOR vulnerabilities tested',
    '✓ SQL injection tested',
    '✓ XSS tested',
    '✓ CSRF tested',
    '✓ Rate limiting tested'
  ]
};

3.7 Latihan Praktikum

Exercise 1: Implement Security Headers

javascript
/**
 * TODO: Implement custom security headers
 * 1. Feature-Policy / Permissions-Policy
 * 2. Expect-CT
 * 3. Report-To (for CSP reporting)
 * 4. Clear-Site-Data for logout
 */

class SecurityHeaders {
  static permissionsPolicy() {
    // Implementasi
  }

  static expectCT() {
    // Implementasi
  }

  static reportTo() {
    // Implementasi
  }

  static clearSiteData() {
    // Implementasi
  }
}

Exercise 2: Advanced Rate Limiting

javascript
/**
 * TODO: Implement advanced rate limiting
 * 1. Redis store for distributed systems
 * 2. Per-user + per-IP combined limits
 * 3. Dynamic limits based on user role
 * 4. Burst allowance
 * 5. Custom key generators
 */

class AdvancedRateLimiter {
  constructor(redis) {
    this.redis = redis;
  }

  async checkLimit(key, limit, window) {
    // Implementasi
  }

  middleware(options) {
    // Implementasi
  }
}

Exercise 3: Security Audit Logger

javascript
/**
 * TODO: Implement comprehensive security audit logging
 * 1. Log all authentication attempts
 * 2. Log all permission changes
 * 3. Log all sensitive data access
 * 4. Log all configuration changes
 * 5. Log all security events
 */

class SecurityAuditLogger {
  logAuthAttempt(email, success, req) {
    // Implementasi
  }

  logPermissionChange(userId, changedBy, oldPermissions, newPermissions) {
    // Implementasi
  }

  logSensitiveDataAccess(userId, resourceType, resourceId) {
    // Implementasi
  }

  logConfigChange(changedBy, changes) {
    // Implementasi
  }
}

Exercise 4: Input Sanitization Library

javascript
/**
 * TODO: Build comprehensive sanitization library
 * 1. HTML sanitization (allow safe tags)
 * 2. URL sanitization
 * 3. Email sanitization
 * 4. Phone number formatting
 * 5. SQL injection prevention
 * 6. NoSQL injection prevention
 */

class SanitizationLibrary {
  static html(html, options) {
    // Implementasi
  }

  static url(url) {
    // Implementasi
  }

  static email(email) {
    // Implementasi
  }

  static phone(phone) {
    // Implementasi
  }

  static sql(input) {
    // Implementasi
  }

  static nosql(input) {
    // Implementasi
  }
}

4. Daftar Pustaka

  1. Express.js Documentation (n.d). Security Best Practices: Securityhttps://expressjs.com
  2. Escape (2024). How to secure APIs build with Express.js. https://escape.tech
  3. TatvaSoft (2025). Node Js Best Practices and Securityhttps://www.tatvasoft.com
  4. Treeindev (2020). Best Practices in Express (Node.js). https://treeindev.net
  5. Belajar Koding (2024). Express.js Cheat Sheetshttps://belajarkoding.com/cheat-sheets/express

Posting Komentar

0 Komentar