Noch ein paar Hardening-Sachen
This commit is contained in:
@@ -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');
|
||||
|
||||
Reference in New Issue
Block a user