Security Matrix
Сводная матрица защит по всем доменам GOLOOT.
1. Summary
Goal: Централизованный обзор всех защитных механизмов для аудита и планирования.
User Value: Быстрая проверка "какие защиты применены к этому действию?" без копания в коде.
2. Rate Limit Configs
Конфигурации из backend/src/common/middleware/rate-limits.middleware.ts:
Все лимиты определены в backend/src/common/constants/validation.ts → RATE_LIMITS.
В dev-режиме автоматически применяется множитель ×10.
| Config | Лимит | Использование |
|---|---|---|
feedback | 1/min | Отправка фидбека — защита от спама |
mutations | 5/min | Изменение данных (create/update/delete) |
achievementClaim | 15/min | Получение наград |
auth | 5/min | Авторизация — защита от брутфорса |
verify | 30/min | Верификация (2FA, email) |
unauth | 20/min | Неавторизованные запросы |
general | 100/min | Общие операции |
content | 200/min | Чтение контента (высокий лимит) |
personalContent | 10/min | Личные данные пользователя |
critical | 5/min | Критичные мутации (UTM create/delete) |
tracking | 60/min | Tracking события (UTM) |
analytics | 30/min | Аналитика запросы |
shortlinks | 100/min | Публичные редиректы |
onboarding | 20/min | Публичный onboarding (subscription check) |
feed | 30/min | Публичный feed событий |
botCheck | 30/min | Проверка статуса бота |
adminApiLimiter | 50/min | Админские API операции |
presetDownloads | 5/min | Скачивание preset файлов |
3. Authentication Types
| Тип | Middleware | Описание |
|---|---|---|
telegram | telegramAuth | Telegram WebApp initData verification |
telegramLight | telegramAuthLight | Telegram auth без ban-check (для апелляций) |
telegram + season | telegramAuth + requireActiveSeason | Telegram auth + проверка активного сезона |
telegram + season + steam | telegramAuth + requireActiveSeason + steam check | Для raffle: требуется верифицированный Steam |
admin | adminAuthMiddleware | JWT + role: admin check |
plugin | pluginAuthMiddleware | Bearer API Key (Rust сервер) |
none | - | Публичный эндпоинт |
4. Content Security Policy (CSP)
TMA работает в iframe Telegram Web, поэтому CSP настроена для совместимости:
CSP включена в режиме enforcement — нарушения блокируются браузером.
| Директива | Значение | Причина |
|---|---|---|
defaultSrc | 'self' | Базовая политика |
scriptSrc | 'self', 'unsafe-inline', telegram.org, *.telegram.org | Telegram SDK + inline scripts |
styleSrc | 'self', 'unsafe-inline' | CSS-in-JS, inline styles |
imgSrc | 'self', data:, https:, blob: | Изображения из разных источников |
connectSrc | 'self', https://api.goloot.online, wss:, https://telegram.org | API + WebSocket + Telegram |
fontSrc | 'self', data: | Шрифты |
frameAncestors | 'self', https://web.telegram.org, https://t.me | Разрешённые iframe parents (TMA) |
formAction | 'self' | Ограничение form submissions |
objectSrc | 'none' | Блокировка object/embed |
baseUri | 'self' | Защита от base tag injection |
Конфигурация: backend/src/server.ts → helmet({ contentSecurityPolicy: {...} })
5. Protection Matrix
- Economy
- Gamification
- Social
- Users
- Admin
- Integrations
- Marketing
| Domain | Action | Rate Limit | Auth | Validation | Atomic | Notes |
|---|---|---|---|---|---|---|
| cases | open | general | telegram | OpenCaseSchema | ✓ | Balance + reward |
| cases | create | mutations | admin | CreateCaseSchema | - | Admin only |
| craft | check | general | telegram | CheckCraftAbilitySchema | - | Read only |
| craft | craft item | mutations | telegram + season | CraftItemSchema | ✓ | Materials + scrap |
| craft | get available | general | telegram | GetCraftableItemsSchema | - | Read only |
| daily-spins | spin | general | telegram | SpinSchema | ✓ | Balance + reward |
| inventory | list | general | telegram | GetInventorySchema | - | Read only |
| inventory | salvage | general | telegram + season | SalvageItemSchema | ✓ | XP grant |
| Domain | Action | Rate Limit | Auth | Validation | Atomic | Notes |
|---|---|---|---|---|---|---|
| buffs | get active | general | telegram | GetActiveBuffsSchema | - | Read only |
| buffs | get history | general | telegram | GetBuffHistorySchema | - | Read only, paginated |
| buffs | activate | mutations | telegram | ActivateBuffSchema | ✓ | Consume item + create buff |
| quests | get list | general | telegram | GetUserQuestsSchema | - | Read only, Lazy Reset |
| quests | get by ID | general | telegram | GetUserQuestByIdSchema | - | Read only |
| quests | claim | achievementClaim | telegram + season | ClaimQuestRewardSchema | ✓ | Reward grant |
| quests | check | general | telegram + season | CheckQuestSchema | - | Telegram subscription check |
| quests | start rust | general | telegram + season | StartRustQuestSchema | - | Rust quest init |
| streaks | get stats | general | telegram | - | - | Read only |
| streaks | claim daily | achievementClaim | telegram + season | - | ✓ | SP grant |
| streaks | get leaderboard | general | telegram | GetLeaderboardQuerySchema | - | Read only |
| seasons | get current | general | telegram | GetCurrentSeasonSchema | - | ACTIVE or COUNTDOWN |
| seasons | get stats | general | telegram | GetSeasonStatsSchema | - | User season stats |
| seasons | get leaderboard | general | telegram | GetLeaderboardSchema | - | Top-10 + user position |
| seasons | end (admin) | mutations | admin + password | AdminForceEndSeasonSchema | ✓ | Rewards + reset |
| seasons | start (admin) | mutations | admin + password | AdminStartSeasonSchema | ✓ | From COUNTDOWN |
| raffle | get current | general | telegram | - | - | Read only |
| raffle | buy ticket | mutations | telegram + season + steam | BuyTicketBodySchema | ✓ | SP deduct + ticket |
| raffle | get history | general | telegram | GetRaffleHistoryQuerySchema | - | Read only |
| achievements | claim | achievementClaim | telegram | ClaimSchema | ✓ | Reward grant |
| Domain | Action | Rate Limit | Auth | Validation | Atomic | Notes |
|---|---|---|---|---|---|---|
| feedback | submit | feedback | telegram | FeedbackSchema | - | 1/min strict |
| feedback | send message | 10/day (app) | telegram | createMessageSchema | ✓ | App-level limit |
| feedback | ban appeal | 1/day (app) | telegramLight | BAN_APPEAL_LIMITS | - | No ban-check |
| feedback | close ticket | - | telegram | ticketIdParamSchema | ✓ | Owner check |
| referrals | create code | general | telegram | CreateReferralCodeSchema | - | Auto-gen if empty |
| referrals | get code | general | none | ReferralCodeParamsSchema | - | Public, read only |
| referrals | get analytics | general | telegram | ReferralAnalyticsQuerySchema | - | Owner check |
| referrals | get my codes | general | telegram | - | - | Auto-create if none |
| referrals | get my stats | general | telegram | GetMyReferralStatsSchema | - | Read only |
| referrals | get my referrals | general | telegram | GetMyReferralsSchema | - | Read only |
| referrals | get config | general | none | - | - | Public, read only |
| feed | get events | feed (30/min) | none | GetFeedQuerySchema | - | Public, read only |
| feed | live stream | feed (30/min) | none | - | - | SSE, public |
| Domain | Action | Rate Limit | Auth | Validation | Atomic | Notes |
|---|---|---|---|---|---|---|
| users/profile | get | general | telegram | GetProfileSchema | - | Streak update side-effect |
| users/stats | get | general | telegram | GetStatsSchema | - | Rank calculation |
| users/feedback | submit | feedback | telegram | FeedbackSchema | - | 1/min, sends TG notification |
| users/statistics | categories | general | telegram | - | - | Quiz stats aggregation |
| users/statistics | all-time | general | telegram | - | - | Cross-season SUM/MAX |
| users/statistics | streak-points | general | telegram | - | - | SP breakdown by source |
| users/steam | set trade-url | general | telegram | UpdateTradeUrlSchema | - | Triggers verification, anti-fraud checks |
| users/steam | delete trade-url | general | telegram | - | - | Clears verification |
| users/verification | get status | general | telegram | - | - | Manual verification check |
| users/withdraw | readiness check | general | telegram | - | - | 7-point check |
| users/rust | online status | general | telegram | - | - | PlayerSession lookup |
| users/settings | get | general | telegram | GetSettingsSchema | - | Auto-create if none |
| users/settings | update | general | telegram | UpdateSettingsSchema | - | Single field |
| onboarding | get status | onboarding (20/min) | none | GetOnboardingStatusSchema | - | Public, subscription check |
| onboarding | complete | onboarding (20/min) | none | CompleteOnboardingSchema | - | Public, validates subscriptions |
| onboarding | refresh | onboarding (20/min) | none | RefreshSubscriptionsSchema | - | Public, testing/troubleshooting |
| Domain | Action | Rate Limit | Auth | Validation | CSRF | Notes |
|---|---|---|---|---|---|---|
| admin-auth | login | auth | none | LoginSchema | - | Password + 2FA |
| admin-* | mutations | mutations | admin | varies | ✓ | All admin writes |
| quizzes | CRUD | adminApiLimiter (50/min) | admin | CreateQuizSchema, UpdateQuizSchema | ✓ | Admin only |
| quizzes | stats | adminApiLimiter (50/min) | admin | GetQuizStatsSchema | - | Cached 5min |
| categories | CRUD | adminApiLimiter (50/min) | admin | CategorySchemas | ✓ | Cascade activation |
| subcategories | CRUD | adminApiLimiter (50/min) | admin | SubcategorySchemas | ✓ | Cascade activation |
| admin-users | list | adminApiLimiter (50/min) | admin | AdminUsersListQuery | - | Paginated, filters |
| admin-users | stats | adminApiLimiter (50/min) | admin | — | - | StatCards data |
| admin-users | details | adminApiLimiter (50/min) | admin | UserIdParam | - | Full user data |
| admin-users | ban | adminApiLimiter (50/min) | admin | BanUserBody | - | With reason |
| admin-users | unban | adminApiLimiter (50/min) | admin | UserIdParam | - | Clear ban |
| admin-users | delete | adminApiLimiter (50/min) | admin | DeleteUserBody | - | Soft delete |
| admin-users | currency | adminApiLimiter (50/min) | admin | UpdateCurrencyBody | - | Scrap/XP/SP |
| admin-users | inventory | adminApiLimiter (50/min) | admin | InventoryQuery | - | Paginated |
| admin-users | histories | adminApiLimiter (50/min) | admin | HistoryQuery | - | Cases/Spins/Quests |
| admin-raffle | get prize pool | general | admin | — | - | Read only |
| admin-raffle | add to pool | mutations | admin | AddToPrizePoolBodySchema | - | Bot inventory check |
| admin-raffle | update pool item | mutations | admin | UpdatePrizePoolItemSchema | - | Weight/status |
| admin-raffle | delete from pool | mutations | admin | — | - | - |
| admin-raffle | get raffles | general | admin | PaginationQuerySchema | - | Paginated |
| admin-raffle | get raffle details | general | admin | — | - | Read only |
| admin-raffle | cancel raffle | mutations | admin | CancelRaffleBodySchema | ✓ | SP refund |
| admin-raffle | create next | mutations | admin | — | ✓ | From prize pool |
| admin-raffle | manual draw | mutations | admin | — | ✓ | Force draw |
| admin-raffle | get bot inventory | general | admin | — | - | Steam bot cache |
| admin-raffle | refresh inventory | mutations | admin | — | - | Steam API call |
| Domain | Action | Rate Limit | Auth | Validation | Atomic | Notes |
|---|---|---|---|---|---|---|
| rust-integration | webhook | — | plugin | RustWebhookPayloadSchema | ✓ | Trusted source |
| rust-integration | get tasks | — | plugin | — | - | Read only |
| rust-integration | list servers | general | admin | — | - | Read only |
| rust-integration | create server | mutations | admin | CreateRustServerSchema | - | Returns API Key |
| rust-integration | update server | mutations | admin | UpdateRustServerSchema | - | - |
| rust-integration | delete server | mutations | admin | DeleteRustServerSchema | ✓ | Cascade if force |
| rust-integration | regenerate key | mutations | admin | — | - | Returns new API Key |
| rust-integration | reveal credentials | mutations | admin + password + 2FA | RevealCredentialsSchema | - | Re-auth required |
| rust-integration | get logs | general | admin | GetServerLogsSchema | - | Paginated |
| telegram | check-bot | botCheck (30/min) | none | CheckBotRegistrationSchema | - | Bot status check |
| telegram | webhook | 100/sec | secret_token | TelegramWebhookSchema | - | TG webhook receiver (see Webhook Security) |
| telegram | create-session | botCheck (30/min) | none | CreateSessionSchema | - | UTM/Referral session |
| telegram | activate-session | botCheck (30/min) | Telegram HMAC | ActivateSessionSchema | ✓ | Bonus grant |
| telegram | quiz-answer | RateLimiter (50/sec + 10/min) | none | — | ✓ | Scrap grant |
| telegram | broadcast | mutations | admin | BroadcastSchema | - | Mass push |
| telegram | push CRUD | mutations | admin | PushNotificationSchemas | - | Admin only |
| telegram | scheduler stats | general | admin | — | - | Read only |
| steam-trade | create withdraw | mutations | telegram | WithdrawalSchema | ✓ | Item reservation |
| steam-trade | check readiness | general | telegram | ReadinessSchema | - | 7-point check |
| steam-trade | get history | general | telegram | — | - | User withdrawals |
| steam-trade | get jobs | general | admin | — | - | All trade jobs |
| steam-trade | cancel job | — | admin | — | ✓ | PENDING only |
| steam-trade | bot inventory | general | admin | — | - | Cached 5min |
| steam-trade | refresh inventory | mutations | admin | — | - | Steam API call |
| Domain | Action | Rate Limit | Auth | Validation | Atomic | Notes |
|---|---|---|---|---|---|---|
| promo-codes | redeem | general | telegram + season | redeemPromoCodeSchema | ✓ | Reward grant |
| promo-codes | get history | general | telegram | — | - | Read only |
| promo-codes | CRUD | mutations | admin | varies | - | Admin only |
| utm-tracking | redirect | shortlinks (100/min) | none | — | - | Public, clean redirect |
| utm-tracking | create campaign | critical (5/min) | admin | UTMParametersSchema | - | Admin only |
| utm-tracking | list campaigns | admin (10/min) | admin | UTMLinksQuerySchema | - | Paginated |
| utm-tracking | toggle/delete | critical (5/min) | admin | — | ✓ | Cascade ShortLinks |
| utm-tracking | analytics | analytics (30/min) | admin | AnalyticsQuerySchema | - | Cached |
| utm-tracking | soft delete value | critical (5/min) | admin | — | - | Audit trail |
6. Security Middleware Stack
Порядок применения middleware в Fastify:
Request
↓
1. Rate Limit (по IP/telegramId)
↓
2. Auth (telegramAuth / adminAuth)
↓
3. CSRF Check (для admin mutations)
↓
4. Ban Check (isBanned)
↓
5. Season Check (requireActiveSeason)
↓
6. Schema Validation
↓
7. Handler
7. Security Principles
Принципы безопасности, которым должен следовать весь код.
SQL Injection Prevention
Prisma ORM защищает от SQL injection по умолчанию, но raw queries требуют внимания.
При использовании $queryRaw / $executeRaw — ТОЛЬКО tagged template literals.
Prisma автоматически экранирует параметры в tagged templates.
// ✅ ПРАВИЛЬНО — параметры экранируются автоматически
const result = await prisma.$queryRaw`
SELECT * FROM users WHERE id = ${userId}
`;
// ✅ ПРАВИЛЬНО — несколько параметров
await prisma.$executeRaw`
UPDATE user_season_stats SET rank = ${rank}
WHERE "seasonId" = ${seasonId} AND id = ${odbc}
`;
// ❌ ОПАСНО — string interpolation = SQL injection
const result = await prisma.$queryRaw(`
SELECT * FROM users WHERE id = '${userId}'
`);
// ❌ ОПАСНО — конкатенация строк
const query = "SELECT * FROM users WHERE name = '" + userName + "'";
Файлы с raw queries: Все используют безопасный паттерн (проверено).
| Файл | Использование |
|---|---|
seasons/repositories/season.repository.ts | Batch rank update (window functions) |
referrals/services/referral-analytics.service.ts | Aggregation queries |
utm/services/utm-analytics.service.ts | Date-based stats |
banners/services/banner-analytics.service.ts | Banner analytics |
IDOR Prevention
Insecure Direct Object Reference (IDOR) — когда пользователь может получить доступ к чужим данным, подставив чужой ID.
userId берётся ТОЛЬКО из request.user (установленного auth middleware), НИКОГДА из params/body/query.
// ✅ ПРАВИЛЬНО — userId из auth middleware
async getProfile(request: FastifyRequest) {
const { userId } = request.user; // Из telegramAuth
return this.service.getProfile(userId);
}
// ✅ ПРАВИЛЬНО — проверка ownership
async getTicket(request: FastifyRequest) {
const { ticketId } = request.params;
const { userId } = request.user;
const ticket = await this.service.getTicket(ticketId);
if (ticket.userId !== userId) {
throw new ForbiddenError('Not your ticket');
}
return ticket;
}
// ❌ ОПАСНО — userId из params (атакующий подставит чужой ID)
async getProfile(request: FastifyRequest) {
const { userId } = request.params; // IDOR vulnerability!
return this.service.getProfile(userId);
}
// ❌ ОПАСНО — userId из body
async updateBalance(request: FastifyRequest) {
const { userId, amount } = request.body; // IDOR vulnerability!
return this.service.addBalance(userId, amount);
}
Исключения:
- Admin endpoints — админ может работать с любым userId (защищено
adminAuthMiddleware) - Public endpoints — данные и так публичные (feed, referral codes)
Input Validation
Валидация входных данных на всех уровнях.
| Уровень | Инструмент | Что валидирует |
|---|---|---|
| Request body | Zod schemas | Типы, форматы, ограничения |
| Route params | Fastify JSON Schema | UUID format, required params |
| Response | Fastify JSON Schema | Структура ответа (убирает лишние поля) |
| Business logic | Service layer | Бизнес-правила (достаточно баланса, не забанен) |
// ✅ ПРАВИЛЬНО — Zod schema для body
export const CreateQuestSchema = z.object({
title: z.string().min(3).max(100),
targetValue: z.number().int().positive(),
rewardScrap: z.number().int().min(0).max(10000),
type: z.nativeEnum(QuestType),
});
// ✅ ПРАВИЛЬНО — Fastify schema для route
fastify.post('/quests', {
schema: {
body: CreateQuestBodySchema,
response: {
200: CreateQuestResponseSchema,
},
},
preHandler: [telegramAuth],
handler: controller.create,
});
// ❌ ОПАСНО — без валидации
fastify.post('/quests', async (request) => {
const data = request.body; // Не валидировано!
return service.create(data);
});
Fastify автоматически удаляет поля, не описанные в response schema. Если добавляешь новое поле в service — добавь его и в schema!
XSS Prevention
Cross-Site Scripting предотвращается на нескольких уровнях:
| Защита | Где применяется | Как работает |
|---|---|---|
| CSP | Backend (helmet) | Блокирует inline scripts из недоверенных источников |
| React escaping | Frontend | Автоматически экранирует output в JSX |
| No dangerouslySetInnerHTML | Frontend | Запрещено в code review |
| Input sanitization | Backend | Zod валидация + типизация |
// ✅ ПРАВИЛЬНО — React экранирует автоматически
function UserName({ name }: { name: string }) {
return <span>{name}</span>; // Безопасно даже если name = "<script>..."
}
// ❌ ОПАСНО — прямой HTML (запрещено в проекте)
function UserBio({ html }: { html: string }) {
return <div dangerouslySetInnerHTML={{ __html: html }} />; // XSS!
}
Проверка: dangerouslySetInnerHTML не найден в frontend/src/.
Plugin Authentication (Rust)
Rust серверы аутентифицируются через API Key, не через rate limiting.
| Механизм | Описание |
|---|---|
| Bearer Token | Authorization: Bearer {apiKey} |
| Server lookup | Ключ → RustServer в БД |
| isActive check | Деактивированные серверы отклоняются |
| Request decoration | request.rustServer = { id, name } |
// Plugin auth middleware
const apiKey = authHeader.slice(7); // "Bearer " prefix
const server = await prisma.rustServer.findUnique({
where: { apiKey },
});
if (!server) return 401; // Invalid key
if (!server.isActive) return 403; // Deactivated
Почему нет Rate Limit:
- Trusted source (только свои серверы)
- API Key = identity (можно отключить конкретный сервер)
- Low traffic (~10-20 req/min на сервер)
Конфигурация: backend/src/domains/rust-integration/middleware/plugin-auth.middleware.ts
Telegram Bot Webhook Security
Telegram webhook endpoint принимает updates от Telegram Bot API. Без защиты атакующий может отправить поддельный HTTP-запрос и выполнить действия от имени бота.
Через модифицированный Telegram-клиент видны callback_data inline-кнопок. Через Telegram Bot API (Postman) можно отправить поддельный webhook-запрос на /api/telegram/webhook, подставив нужный callback_data и chat.id.
Защита (defense in depth):
| Уровень | Механизм | Что защищает |
|---|---|---|
| 1. Webhook Secret Token | X-Telegram-Bot-Api-Secret-Token header | Подделка webhook-запросов |
| 2. Admin User Whitelist | TELEGRAM_ADMIN_IDS + ctx.from.id | Подмена admin-пользователя |
| 3. Budget Amount Validation | Whitelist допустимых сумм | Произвольные суммы через callback_data |
| 4. Rate Limiting | 100 req/sec на webhook endpoint | DoS через массовые запросы |
Webhook Secret Token:
- При
setWebhook()передаётсяsecret_token - Telegram включает его в каждый запрос как заголовок
X-Telegram-Bot-Api-Secret-Token - Backend проверяет заголовок перед обработкой update
- Без валидного токена — 401 Unauthorized
Admin Callback Protection:
- Admin inline-кнопки (budget_add, season_pause, season_ok) доступны в admin-группе Telegram
- Двойная проверка:
chat.id===TELEGRAM_GROUP_IDANDfrom.idinTELEGRAM_ADMIN_IDS - Все admin-действия логируются с
adminUserId
Переменные окружения:
| Переменная | Обязательна | Описание |
|---|---|---|
TELEGRAM_WEBHOOK_SECRET | Нет (dev), Да (prod) | 64-символьный hex-токен (openssl rand -hex 32) |
TELEGRAM_ADMIN_IDS | Нет | Comma-separated Telegram user IDs для admin-кнопок |
TELEGRAM_GROUP_ID | Нет | ID admin-группы для уведомлений |
Конфигурация:
- Webhook route:
backend/src/domains/telegram/routes/telegram-bot.routes.ts - Admin callbacks:
backend/src/domains/telegram/handlers/admin-callback.handler.ts - Secret config:
backend/src/common/utils/secrets.service.ts
8. Related
- TMA Auth Architecture — архитектура авторизации TMA (HMAC vs JWT)
- Settings — настройки пользователя
- Steam Verification — верификация Steam-аккаунтов
- Seasons — система сезонов и рейтингов
- Quests — система квестов и заданий
- Buffs — система временных бонусов
- Streaks & Raffle — система лояльности и розыгрышей
- Quizzes — система викторин для TG канала
- Live Feed — публичная лента событий (SSE)
- Referrals — реферальная система и пассивный доход
- Feedback — система обратной связи и поддержки
- Promo Codes — система промокодов
- UTM Tracking — система маркетинговых ссылок
- Docs Access — система доступа к документации
- Docs Deployment — CI/CD для документации
- Rust Integration — интеграция с Rust серверами
- Steam Trade Bot — автоматизированный вывод скинов в Steam
- Telegram Bot — Telegram бот, push-уведомления, квизы