tractatus/src/utils/security-logger.js
TheFlow afc4bc5a1b security: implement Quick Wins security middleware (inst_041-046)
- Add security headers middleware (CSP, HSTS, X-Frame-Options, etc.)
- Add rate limiting (100 req/15min public, 5 req/min forms)
- Add input validation and sanitization middleware
- Add response sanitization (hide stack traces, remove sensitive fields)
- Add centralized security event logging to audit trail
- Disable CSRF (deprecated package, will implement modern solution in Phase 3)
- Update security logger to use HOME-based log path

Implements: inst_041, inst_042, inst_043, inst_044, inst_045, inst_046
Refs: docs/plans/security-implementation-roadmap.md
2025-10-14 15:18:49 +13:00

72 lines
2.3 KiB
JavaScript

/**
* Security Event Logger (inst_046 - Quick Win Version)
* Centralized logging for all security events
*
* QUICK WIN: Simple file-based logging with JSON format
* Full version in Phase 5 will add ProtonMail/Signal alerts
*/
const fs = require('fs').promises;
const path = require('path');
const SECURITY_LOG_PATH = process.env.SECURITY_LOG_PATH ||
(process.env.HOME ? `${process.env.HOME}/var/log/tractatus/security-audit.log` : '/var/log/tractatus/security-audit.log');
/**
* Log a security event to audit trail
*
* @param {Object} event - Security event details
* @param {string} event.type - Event type (e.g., 'rate_limit_violation')
* @param {string} event.sourceIp - Source IP address
* @param {string} event.userId - User ID (if authenticated)
* @param {string} event.endpoint - Request endpoint
* @param {string} event.userAgent - User agent string
* @param {Object} event.details - Additional event details
* @param {string} event.action - Action taken (e.g., 'blocked', 'logged')
* @param {string} event.severity - Severity level ('low', 'medium', 'high', 'critical')
*/
async function logSecurityEvent(event) {
const logEntry = {
timestamp: new Date().toISOString(),
event_type: event.type || 'unknown',
source_ip: event.sourceIp || 'unknown',
user_id: event.userId || 'anonymous',
endpoint: event.endpoint || 'unknown',
user_agent: event.userAgent || 'unknown',
violation_details: event.details || {},
action_taken: event.action || 'logged',
severity: event.severity || 'medium'
};
const logLine = JSON.stringify(logEntry) + '\n';
try {
// Ensure log directory exists
const logDir = path.dirname(SECURITY_LOG_PATH);
await fs.mkdir(logDir, { recursive: true, mode: 0o750 });
// Append to log file
await fs.appendFile(SECURITY_LOG_PATH, logLine, { encoding: 'utf-8' });
} catch (error) {
// Fallback to console if file logging fails
console.error('[SECURITY LOGGER ERROR]', error.message);
console.error('[SECURITY EVENT]', logEntry);
}
}
/**
* Helper: Extract client IP from request (handles proxies)
*/
function getClientIp(req) {
return (
req.ip ||
req.headers['x-forwarded-for']?.split(',')[0]?.trim() ||
req.connection.remoteAddress ||
'unknown'
);
}
module.exports = {
logSecurityEvent,
getClientIp
};