Security Logging and Monitoring in Express Applications

Introduction

Welcome to the final lesson in our Server-Side Request Forgery (SSRF) Prevention in Express course! In this lesson, we'll explore security logging and monitoring in depth. Effective logging and monitoring are crucial components of a comprehensive security strategy, as they help you detect, investigate, and respond to security incidents promptly. Let's dive in and discover how to implement these practices in your Express applications! 📊

The Role of Security Logging

Security logging is the practice of recording events related to security concerns within your application. Properly implemented logs serve multiple purposes:

  1. Detecting Security Incidents: Logs can reveal suspicious activities that may indicate ongoing attacks.
  2. Investigating Breaches: After a security incident, logs provide valuable data for forensic analysis.
  3. Compliance Requirements: Many regulatory frameworks require specific logging practices.
  4. System Auditing: Logs help track user activities and system changes over time.

Let's implement a comprehensive logging system using the popular Winston library:

import express from 'express';
import winston from 'winston';
import expressWinston from 'express-winston';
import path from 'path';

const app = express();
app.use(express.json());

// Configure logging format and transports
const logger = winston.createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  defaultMeta: { service: 'web-service' },
  transports: [
    // Console transport for development
    new winston.transports.Console({
      format: winston.format.combine(
        winston.format.colorize(),
        winston.format.simple()
      )
    }),
    // File transport for persistent logs
    new winston.transports.File({ 
      filename: path.join(__dirname, 'logs/error.log'), 
      level: 'error' 
    }),
    new winston.transports.File({ 
      filename: path.join(__dirname, 'logs/combined.log')
    })
  ]
});

// Log all HTTP requests
app.use(expressWinston.logger({
  winstonInstance: logger,
  meta: true,
  msg: 'HTTP {{req.method}} {{req.url}}',
  expressFormat: true,
  colorize: false
}));

// Add custom security logging middleware
app.use((req, res, next) => {
  // Log potentially suspicious activities
  if (req.body?.url || req.query?.url) {
    logger.warn('URL parameter detected', {
      ip: req.ip,
      url: req.body.url || req.query.url,
      method: req.method,
      path: req.path,
      userAgent: req.headers['user-agent']
    });
  }
  next();
});

// Example route
app.get('/', (req, res) => {
  res.send('Hello, world!');
});

// Error logging middleware
app.use(expressWinston.errorLogger({
  winstonInstance: logger
}));

app.listen(3000, () => {
  logger.info('Server running on port 3000');
});

This code sets up a robust logging system using Winston. It logs all HTTP requests and errors to both the console and files, making it easier to monitor and analyze application activities.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal