nakama/backend/middleware/security.js

101 lines
3.2 KiB
JavaScript
Raw Normal View History

2025-11-04 21:51:05 +00:00
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
};