Files
SQS-service/doc/decisions/resource-limits-plan.md
T
Naeel b9d434bcc5 v0.1.16: JWT auth via nubes API, auto-provisioning, UI login
- app/auth/jwt.go: ParseJWTClaims, TenantIDFromSub (sless-compatible SHA256), PingNubesAPI
- app/admin/admin.go: POST /ui/api/auth endpoint, jwtMiddleware for /ui/api/*
- app/tenant/tenant_store.go: NubesSub/Email fields, GetBySub, CreateFromJWT
- app/ui/index.html: login page, email in navbar, JWT session in localStorage
- deployments/k8s/deployment.yaml: v0.1.16, NUBES_ENDPOINT env
- doc/decisions/resource-limits-plan.md: 20 vulnerabilities audit
- Fix: /ui/api/auth moved to subrouter (gorilla/mux PathPrefix conflict)
2026-04-10 18:35:19 +03:00

8.9 KiB
Raw Blame History

Решение: Защита от ресурсного исчерпания (Resource Exhaustion Protection)

Дата: 2026-04-10
Статус: ПЛАН (на согласовании)
Автор анализа: GitHub Copilot (Claude Opus 4.6)


Контекст

Проведён полный аудит shared-sqs на уязвимости типа DoS / resource exhaustion. Найдено 20 уязвимостей (2 Critical, 8 High, 8 Medium, 2 Low).

Главная угроза: один тенант может положить сервис для всех — через создание огромных очередей, бесконечный long polling, отсутствие валидации размеров.

Кросс-тенантный доступ к данным невозможен — изоляция через составной ключ работает корректно.


Найденные уязвимости

🔴 CRITICAL

# Уязвимость Где Как эксплуатировать
1 Публичный Admin API без auth /ui/api/* Любой может создавать тенантов, очереди, слать сообщения, удалять данные без токена
2 Batch message size bypass send_message_batch.go SendMessageBatchV1 не проверяет размер тела каждого сообщения; 10×256MB = 2.5GB в одном запросе

🟠 HIGH

# Уязвимость Где AWS лимит
3 QueueName без валидации create_queue.go Макс 80 chars, [a-zA-Z0-9_-]
4 WaitTimeSeconds без потолка receive_message.go 020 сек
5 ReceiveMessageWaitTimeSeconds без потолка queue_attributes.go 020 сек
6 DelaySeconds без потолка queue_attributes.go 0900 сек
7 VisibilityTimeout без потолка queue_attributes.go 043200 сек
8 MaxNumberOfMessages без потолка receive_message.go 110
9 Message attributes без лимита requests.go Макс 10, общий размер ≤256KB
10 Data race в GetQueueUrlV1 get_queue_url.go Нет RLock перед чтением

🟡 MEDIUM

# Уязвимость Где Последствие
11 Нет лимита сообщений в очереди все send handlers OOM при миллионах сообщений
12 Нет лимита на создание тенантов admin.go OOM при 100K тенантов
13 FIFO group lock без таймаута receive_message.go Group заблокирован навсегда
14 Duplicates map без очистки models.go Утечка памяти
15 BatchEntryId без валидации длины send_message_batch.go Раздутые ключи
16 DeduplicationID без валидации send_message_batch.go 128 chars макс по AWS
17 GroupID без валидации send_message.go 128 chars макс по AWS
18 Redis serialization без лимита redis.go Redis OOM при гигантских очередях

🟢 LOW

# Уязвимость Где
19 {account} в URL не валидируется router.go
20 ReceiptHandle не валидируется по формату delete_message.go

План реализации

Фаза 1 — КРИТИЧЕСКОЕ (блокирует production)

Цель: устранить уязвимости, позволяющие анонимную атаку.

Задача Файлы Сложность Что делать
1.1 Защитить публичный API admin.go, router.go Низкая Добавить опцию: либо bearer auth на /ui/api/*, либо убрать write-эндпоинты из public routes, оставив только read
1.2 Валидация размера в batch send_message_batch.go Низкая Добавить проверку len(entry.MessageBody) > queue.MaximumMessageSize в цикле по entries
1.3 RLock в GetQueueUrl get_queue_url.go Низкая Обернуть чтение SyncQueues в RLock()/RUnlock()

Фаза 2 — AWS-совместимые лимиты (валидация параметров)

Цель: привести параметры к стандартам AWS SQS. Создать единый пакет validation.

Задача Файлы Что делать
2.1 Валидация QueueName create_queue.go Макс 80 chars, regex ^[a-zA-Z0-9_-]+(\.fifo)?$
2.2 WaitTimeSeconds cap receive_message.go Clamp к 020
2.3 ReceiveMessageWaitTimeSeconds cap queue_attributes.go Clamp к 020
2.4 DelaySeconds cap queue_attributes.go Clamp к 0900
2.5 VisibilityTimeout cap queue_attributes.go Clamp к 043200
2.6 MaxNumberOfMessages cap receive_message.go Clamp к 110
2.7 Message attributes limit requests.go, send_message.go, send_message_batch.go Макс 10 атрибутов, общий размер ≤256KB
2.8 DeduplicationID/GroupID length send_message.go, send_message_batch.go Макс 128 chars каждый

Фаза 3 — Per-tenant resource limits

Цель: один тенант не может выжрать все ресурсы.

Задача Файлы Что делать
3.1 Макс сообщений в очереди send_message.go, send_message_batch.go Лимит per queue (напр. 120,000 — как AWS standard)
3.2 Макс суммарный размер per tenant tenant_helpers.go Счётчик bytes per tenant; отказ при превышении
3.3 Rate limiting per tenant Новый middleware Token bucket или sliding window; напр. 300 req/sec per tenant
3.4 Макс тенантов в системе admin.go, tenant_store.go Глобальный лимит (конфигурируемый)
3.5 HTTP request body size limit router.go или middleware http.MaxBytesReader — напр. 1MB на запрос

Фаза 4 — Стабильность и очистка

Цель: утечки памяти и deadlock-сценарии.

Задача Файлы Что делать
4.1 FIFO group lock timeout models.go, receive_message.go Таймаут = VisibilityTimeout очереди. Горутина чистит expired locks
4.2 Duplicates map cleanup models.go Горутина-ticker каждые 30 сек, удаляет записи старше 5 мин
4.3 Redis size guard redis.go Не сохранять в Redis если len(data) > 50MB; логировать warning
4.4 {account} валидация router.go или handlers Проверять что {account} == tenant.ID из context

Порядок действий (рекомендация)

Фаза 1 (Critical) → тесты → деплой
    ↓
Фаза 2 (AWS limits) → тесты → деплой
    ↓
Фаза 3 (Per-tenant) → тесты → деплой
    ↓
Фаза 4 (Stability) → тесты → деплой

Каждая фаза — отдельный коммит/PR с тестами.


Что НЕ делаем (и почему)

Отброшено Причина
WAF / Nginx rate limit Overkill для текущего масштаба; лучше in-app
Подпись проверки (HMAC) Сервис эмулирует SQS — подпись не проверяется by design (как LocalStack)
Шифрование сообщений at rest Redis на localhost, не критично на этом этапе
Горизонтальное масштабирование Другая задача; лимиты работают и в single-pod

AWS SQS лимиты (справка)

Параметр AWS лимит
Queue name length 80 chars
Queue name chars [a-zA-Z0-9_-] (+ .fifo суффикс)
Message body 256 KB
Message attributes 10, общий размер ≤ 256 KB
MaxNumberOfMessages 110
WaitTimeSeconds 020
DelaySeconds 0900
VisibilityTimeout 043200 (12 часов)
MessageRetentionPeriod 601,209,600 (14 дней)
Messages per queue ~120,000 in-flight
DeduplicationID 128 chars
GroupID 128 chars
Batch size 10 entries