Noch ein paar Hardening-Sachen

This commit is contained in:
2025-09-25 14:08:45 +00:00
parent 744488fb5b
commit da9d08c149
4 changed files with 80 additions and 67 deletions

View File

@@ -30,28 +30,44 @@ const limiter = rateLimit({
});
app.use(limiter);
// CORS configuration - support comma separated origins in CORS_ORIGIN
// NOTE: In docker-compose we temporarily set CORS_ORIGIN="*" for troubleshooting.
// Narrow this down for production: e.g. CORS_ORIGIN="http://esprimo:3000,http://localhost:3000".
// CORS Hardening
// Supports comma separated origins. Wildcard '*' only allowed if ALLOW_INSECURE_CORS=1 and not in production.
const insecureOverride = process.env.ALLOW_INSECURE_CORS === '1';
const isProd = process.env.NODE_ENV === 'production';
let allowedOrigins: string[] = [];
if (config.cors.origin === '*') {
allowedOrigins = ['*'];
} else if (config.cors.origin.includes(',')) {
if (config.cors.origin.includes(',')) {
allowedOrigins = config.cors.origin.split(',').map(o => o.trim()).filter(Boolean);
} else if (config.cors.origin === '*' && (!isProd || insecureOverride)) {
allowedOrigins = ['*'];
} else {
allowedOrigins = [config.cors.origin];
}
// Always add defaults if not already present
['http://localhost:5173','http://localhost:3000'].forEach(def => {
if (!allowedOrigins.includes(def) && !allowedOrigins.includes('*')) allowedOrigins.push(def);
});
// De-dupe & normalize trailing slashes
allowedOrigins = Array.from(new Set(allowedOrigins.map(o => o.replace(/\/$/, ''))));
// Auto-add common localhost dev origins if not prod and not wildcard
if (!isProd && !allowedOrigins.includes('*')) {
['http://localhost:5173','http://localhost:3000'].forEach(def => {
if (!allowedOrigins.includes(def)) allowedOrigins.push(def);
});
}
// If in production and wildcard attempted without override, remove it
if (isProd && allowedOrigins.includes('*') && !insecureOverride) {
console.warn('[CORS] Wildcard removed in production. Set CORS_ORIGIN explicitly or ALLOW_INSECURE_CORS=1 (NOT RECOMMENDED).');
allowedOrigins = allowedOrigins.filter(o => o !== '*');
}
app.use(cors({
origin: (origin, callback) => {
if (!origin) return callback(null, true); // non-browser (curl, server-side)
if (allowedOrigins.includes('*') || allowedOrigins.includes(origin)) return callback(null, true);
return callback(new Error(`CORS blocked for origin ${origin}`));
if (!origin) return callback(null, true); // Non-browser / same-origin
if (allowedOrigins.includes('*') || allowedOrigins.includes(origin.replace(/\/$/, ''))) {
return callback(null, true);
}
console.warn(`[CORS] Blocked origin: ${origin}`);
return callback(new Error('CORS not allowed for this origin'));
},
credentials: true,
}));
@@ -60,10 +76,11 @@ app.use(cors({
app.use((req, res, next) => {
const origin = req.headers.origin;
const normalized = origin?.replace(/\/$/, '');
if (allowedOrigins.includes('*')) {
res.header('Access-Control-Allow-Origin', origin || '*');
} else if (origin && allowedOrigins.includes(origin)) {
res.header('Access-Control-Allow-Origin', origin);
} else if (normalized && allowedOrigins.includes(normalized)) {
res.header('Access-Control-Allow-Origin', normalized);
}
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');