fix: Harden security - CORS, XSS, file uploads, error handling
- Restrict no-origin CORS bypass to development only - Activate xss-clean middleware for input sanitization - Add MIME type whitelist and filename sanitization to file uploads - Reduce project upload limit from 50MB to 20MB - Stop leaking stack traces in error responses Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,19 +16,42 @@ if (!fs.existsSync(uploadsDir)) {
|
||||
fs.mkdirSync(uploadsDir, { recursive: true });
|
||||
}
|
||||
|
||||
const ALLOWED_FILE_TYPES = [
|
||||
'application/pdf',
|
||||
'application/msword',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'application/vnd.ms-excel',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
'text/plain',
|
||||
'text/csv',
|
||||
];
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
cb(null, uploadsDir);
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
// Sanitize filename to prevent path traversal
|
||||
const sanitized = path.basename(file.originalname).replace(/[^a-zA-Z0-9._-]/g, '_');
|
||||
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
|
||||
cb(null, uniqueSuffix + '-' + file.originalname);
|
||||
cb(null, uniqueSuffix + '-' + sanitized);
|
||||
}
|
||||
});
|
||||
|
||||
const upload = multer({
|
||||
storage,
|
||||
limits: { fileSize: 10 * 1024 * 1024 }, // 10MB max
|
||||
fileFilter: (req, file, cb) => {
|
||||
if (ALLOWED_FILE_TYPES.includes(file.mimetype)) {
|
||||
cb(null, true);
|
||||
} else {
|
||||
cb(new Error('Nepovolený typ súboru. Povolené: PDF, Word, Excel, obrázky, CSV, TXT.'));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Validation schemas
|
||||
|
||||
@@ -10,10 +10,33 @@ import { createProjectSchema, updateProjectSchema } from '../validators/crm.vali
|
||||
import { z } from 'zod';
|
||||
|
||||
// Configure multer for file uploads (memory storage)
|
||||
const ALLOWED_FILE_TYPES = [
|
||||
'application/pdf',
|
||||
'application/msword',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'application/vnd.ms-excel',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'application/vnd.ms-powerpoint',
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
'text/plain',
|
||||
'text/csv',
|
||||
];
|
||||
|
||||
const upload = multer({
|
||||
storage: multer.memoryStorage(),
|
||||
limits: {
|
||||
fileSize: 50 * 1024 * 1024, // 50MB max
|
||||
fileSize: 20 * 1024 * 1024, // 20MB max
|
||||
},
|
||||
fileFilter: (req, file, cb) => {
|
||||
if (ALLOWED_FILE_TYPES.includes(file.mimetype)) {
|
||||
cb(null, true);
|
||||
} else {
|
||||
cb(new Error('Nepovolený typ súboru. Povolené: PDF, Word, Excel, PowerPoint, obrázky, CSV, TXT.'));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user