# Решение: Защита от ресурсного исчерпания (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` | 0–20 сек | | 5 | ReceiveMessageWaitTimeSeconds без потолка | `queue_attributes.go` | 0–20 сек | | 6 | DelaySeconds без потолка | `queue_attributes.go` | 0–900 сек | | 7 | VisibilityTimeout без потолка | `queue_attributes.go` | 0–43200 сек | | 8 | MaxNumberOfMessages без потолка | `receive_message.go` | 1–10 | | 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 к 0–20 | | 2.3 ReceiveMessageWaitTimeSeconds cap | `queue_attributes.go` | Clamp к 0–20 | | 2.4 DelaySeconds cap | `queue_attributes.go` | Clamp к 0–900 | | 2.5 VisibilityTimeout cap | `queue_attributes.go` | Clamp к 0–43200 | | 2.6 MaxNumberOfMessages cap | `receive_message.go` | Clamp к 1–10 | | 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 | 1–10 | | WaitTimeSeconds | 0–20 | | DelaySeconds | 0–900 | | VisibilityTimeout | 0–43200 (12 часов) | | MessageRetentionPeriod | 60–1,209,600 (14 дней) | | Messages per queue | ~120,000 in-flight | | DeduplicationID | 128 chars | | GroupID | 128 chars | | Batch size | 10 entries |