101 lines
3.2 KiB
JavaScript
101 lines
3.2 KiB
JavaScript
const helmet = require('helmet');
|
|
const mongoSanitize = require('express-mongo-sanitize');
|
|
const xss = require('xss-clean');
|
|
const hpp = require('hpp');
|
|
const rateLimit = require('express-rate-limit');
|
|
const config = require('../config');
|
|
|
|
// Настройка Helmet для безопасности headers
|
|
const helmetConfig = helmet({
|
|
contentSecurityPolicy: {
|
|
directives: {
|
|
defaultSrc: ["'self'"],
|
|
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
scriptSrc: ["'self'", "https://telegram.org", "'unsafe-inline'"],
|
|
imgSrc: ["'self'", "data:", "https:", "blob:"],
|
|
connectSrc: ["'self'", "https://api.telegram.org", "https://e621.net", "https://gelbooru.com"],
|
|
fontSrc: ["'self'", "data:"],
|
|
objectSrc: ["'none'"],
|
|
// Запретить использование консоли и eval
|
|
scriptSrcAttr: ["'none'"],
|
|
baseUri: ["'self'"],
|
|
formAction: ["'self'"],
|
|
frameAncestors: ["'none'"],
|
|
upgradeInsecureRequests: config.isProduction() ? [] : null,
|
|
},
|
|
},
|
|
crossOriginEmbedderPolicy: false,
|
|
crossOriginResourcePolicy: { policy: "cross-origin" },
|
|
// Запретить использование консоли
|
|
noSniff: true,
|
|
xssFilter: true
|
|
});
|
|
|
|
// Sanitize MongoDB операторы (защита от NoSQL injection)
|
|
const sanitizeMongo = mongoSanitize({
|
|
replaceWith: '_',
|
|
onSanitize: ({ req, key }) => {
|
|
console.warn(`⚠️ Sanitized MongoDB operator in ${req.path} at key: ${key}`);
|
|
}
|
|
});
|
|
|
|
// XSS защита
|
|
const xssProtection = xss();
|
|
|
|
// Защита от HTTP Parameter Pollution
|
|
const hppProtection = hpp();
|
|
|
|
// Строгий rate limit для авторизации
|
|
const strictAuthLimiter = rateLimit({
|
|
windowMs: 15 * 60 * 1000, // 15 минут
|
|
max: 5, // 5 попыток
|
|
message: 'Слишком много попыток авторизации, попробуйте позже',
|
|
standardHeaders: true,
|
|
legacyHeaders: false,
|
|
skipSuccessfulRequests: true,
|
|
});
|
|
|
|
// Rate limit для создания постов (защита от спама)
|
|
const strictPostLimiter = rateLimit({
|
|
windowMs: 60 * 60 * 1000, // 1 час
|
|
max: 10, // 10 постов
|
|
message: 'Превышен лимит создания постов, попробуйте позже',
|
|
standardHeaders: true,
|
|
legacyHeaders: false,
|
|
skipSuccessfulRequests: true,
|
|
});
|
|
|
|
// Rate limit для файлов
|
|
const fileUploadLimiter = rateLimit({
|
|
windowMs: 60 * 60 * 1000, // 1 час
|
|
max: 50, // 50 загрузок
|
|
message: 'Превышен лимит загрузки файлов',
|
|
standardHeaders: true,
|
|
legacyHeaders: false,
|
|
});
|
|
|
|
// DDoS защита - агрессивный rate limit
|
|
const ddosProtection = rateLimit({
|
|
windowMs: 60 * 1000, // 1 минута
|
|
max: 100, // 100 запросов в минуту
|
|
message: 'Слишком много запросов, попробуйте позже',
|
|
standardHeaders: true,
|
|
legacyHeaders: false,
|
|
skip: (req) => {
|
|
// Пропускать health check
|
|
return req.path === '/health';
|
|
}
|
|
});
|
|
|
|
module.exports = {
|
|
helmetConfig,
|
|
sanitizeMongo,
|
|
xssProtection,
|
|
hppProtection,
|
|
strictAuthLimiter,
|
|
strictPostLimiter,
|
|
fileUploadLimiter,
|
|
ddosProtection
|
|
};
|
|
|