Import source: backend/src/middleware/csrf
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import type { RequestHandler } from 'express';
|
||||
import { env } from '../config/env.js';
|
||||
import { HttpError } from './errorHandler.js';
|
||||
|
||||
/**
|
||||
* Strict origin-based CSRF protection for mutating HTTP requests.
|
||||
* Compares request Origin/Referer against the configured frontendUrl.
|
||||
*/
|
||||
export const csrfProtection: RequestHandler = (req, _res, next) => {
|
||||
// Safe methods do not modify state and are exempt from CSRF checks
|
||||
if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const origin = (req.headers.origin || req.headers.referer) as string;
|
||||
if (!origin) {
|
||||
// If no origin/referer header is sent (e.g. direct curl/scripts), we permit it
|
||||
// because CSRF requires a browser to automatically attach credentials (cookies)
|
||||
// on cross-origin requests. Direct API consumers sending keys/tokens are not susceptible to CSRF.
|
||||
return next();
|
||||
}
|
||||
|
||||
try {
|
||||
const originUrl = new URL(origin);
|
||||
const frontendUrl = new URL(env.frontendUrl);
|
||||
if (originUrl.host !== frontendUrl.host) {
|
||||
throw new HttpError(403, 'CSRF_DETECTED', 'Security policy violation: cross-site request blocked');
|
||||
}
|
||||
} catch {
|
||||
throw new HttpError(403, 'CSRF_DETECTED', 'Security policy violation: malformed origin identifier');
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
Reference in New Issue
Block a user