37 lines
1.1 KiB
TypeScript
37 lines
1.1 KiB
TypeScript
import { Request, Response, NextFunction } from 'express';
|
||
import { verifyCsrfToken, isCsrfConfigured } from '../services/csrf.service';
|
||
import { logger } from '../lib/logger';
|
||
|
||
const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
|
||
|
||
export function csrfMiddleware(req: Request, res: Response, next: NextFunction): void {
|
||
if (SAFE_METHODS.has(req.method)) {
|
||
next();
|
||
return;
|
||
}
|
||
|
||
// If CSRF is not configured (Vault down при старте) — пропускаем, чтобы не блокировать сервис.
|
||
// В логах будет warning — легко заметить.
|
||
if (!isCsrfConfigured()) {
|
||
logger.warn('CSRF check skipped: secret not loaded');
|
||
next();
|
||
return;
|
||
}
|
||
|
||
const token = req.cookies?.csrf_token || req.headers['x-csrf-token'];
|
||
|
||
if (!token || typeof token !== 'string') {
|
||
res.status(403).json({ success: false, error: 'CSRF token missing' });
|
||
return;
|
||
}
|
||
|
||
const result = verifyCsrfToken(token);
|
||
if (!result.valid) {
|
||
logger.warn(`CSRF validation failed: ${result.reason}`);
|
||
res.status(403).json({ success: false, error: 'Invalid CSRF token' });
|
||
return;
|
||
}
|
||
|
||
next();
|
||
}
|