GraphQL API существенно отличается от традиционных REST-эндпоинтов по профилю уязвимости к DDoS-атакам. Основная проблема заключается в том, что один запрос может требовать очень большого объёма вычислительных ресурсов на бэкенде, даже если сам запрос по размеру составляет всего несколько сотен байт.

Почему GraphQL особенно уязвим к сложным атакам на исчерпание ресурсов
Главные векторы атак на GraphQL-серверы в 2024–2025 годах:
- Очень глубокие и/или широкие запросы (deep & wide queries)
- Запросы с большим количеством алиасов
- Массовое использование полей с высокой вычислительной сложностью (особенно connection-модели с relay-спецификацией)
- Атаки через introspection + __schema/__type + поля deprecated
- Batch-атаки (много запросов в одном HTTP-запросе)
- Атаки через persisted queries, когда злоумышленник угадывает/перебирает хэши
Компания «Нева-Автоматизация» является системным интегратором в сфере ИТ и информационной безопасности и занимается проектированием, внедрением и сопровождением комплексных решений для защиты корпоративной инфраструктуры и онлайн-сервисов, включая защита от DDoS атак с использованием специализированных платформ и облачных сервисов Kaspersky DDoS Protection, Solar Anti DDoS, МТС RED Anti DDoS, VK Cloud AntiDDoS и Qrator.AntiDDoS; в рамках своей деятельности компания выполняет анализ сетевого трафика, настройку мониторинга и фильтрации, организацию центров очистки трафика, а также обеспечивает бесперебойную работу веб-ресурсов, серверов и критически важных ИТ-систем для бизнеса и государственных организаций по всей России.
Базовый набор защит, который должен быть на всех продакшен GraphQL API в 2025 году
-
Жёсткое ограничение глубины запроса + ограничение количества полей + ограничение псевдонимов
Большинство современных серверов GraphQL позволяют установить максимальную глубину запроса (max depth) и максимальное количество полей (max field count). Рекомендуемые консервативные значения для большинства бизнес-приложений в 2025 году: • максимальная глубина — 6–10 • максимальное количество полей в запросе — 250–400 • максимальное количество алиасов — 150–250 • максимальное количество значений в любом list-аргументе (first/last) — 50–100
Эти лимиты одновременно отсекают ~95–98% типичных «глубоких» атак, при этом сохраняют возможность работы большинства легитимных клиентов.
-
Ограничение сложности запроса (query cost/complexity analysis)
Самый эффективный современный подход — внедрение системы оценки стоимости запроса (query cost budgeting). Наиболее популярные реализации:
- graphql-cost-analysis (node)
- graphql-query-complexity (node)
- @jenyus-org/graphql-query-cost-analysis (typescript)
- Apollo Server built-in cost directive
- Hasura internal cost model
- graphql-java-cost-analysis
Типичные рекомендуемые потолки в 2025 году для публичных API:
- 100–300 условных единиц сложности для бесплатного/анонимного доступа
- 800–2500 единиц для авторизованных пользователей
- 4000–12000 единиц для внутренних/сервис-к-сервису запросов (при наличии жёсткой аутентификации)
Важный момент: стоимость полей должна быть явно задокументирована для разработчиков фронтенда.
Дополнительные уровни защиты (рекомендуется для средних и крупных проектов)
- Rate limiting на нескольких уровнях одновременно:
- IP → 60–300 запросов/мин (очень консервативно для публичных API)
- IP + User-Agent → 400–800 запросов/мин
- По Bearer-токену / API-ключу → 800–3000 запросов/мин
- По user_id (после авторизации) → 1500–8000 запросов/мин
- Отдельный лимит на количество операций в batch-запросе Текущие разумные значения: 5–12 запросов в одном батче для публичного доступа, 20–50 для авторизованного.
- Запрет или жёсткое ограничение introspection для анонимных пользователей Большинство успешных атак 2023–2025 годов начинались именно с изучения схемы через introspection.
- Таймаут выполнения запроса на уровне GraphQL-сервера Очень важная и часто недооцениваемая мера. Рекомендуемые значения: 2–6 секунд для публичного API, 8–15 секунд для авторизованного трафика.
Практическая последовательность внедрения защит (от самого быстрого результата к более сложному)
- Внедрить жёсткие лимиты глубины + полей + алиасов (обычно 1–3 часа работы)
- Включить максимальный таймаут выполнения запроса (30 мин – 1 час)
- Запретить introspection анонимным пользователям (15–40 мин)
- Внедрить самую простую форму rate limiting по IP (1–4 часа)
- Добавить подсчёт стоимости запроса и лимиты по сложности (2–10 дней в зависимости от стека)
- Настроить многоуровневый rate limiting (IP + токен + user_id) (3–14 дней)
- Внедрить анализ и блокировку по сигнатурам самых популярных атакующих запросов (WAF-подход)
Краткий чек-лист «Что проверить прямо сегодня»
- Есть ли лимит глубины > 12–15? → очень плохо
- Есть ли лимит количества полей > 500–600? → плохо
- Можно ли анонимно сделать introspection? → плохо
- Есть ли таймаут выполнения запроса > 10 секунд? → плохо
- Есть ли хотя бы простой rate limit по IP? → очень плохо, если нет
- Используется ли расчёт стоимости запроса? → если нет, то это самая большая текущая угроза
Хорошая новость 2025 года в том, что большинство современных фреймворков и хостинговых решений (Apollo, Hasura, Grafbase, StepZen, WunderGraph, Hive, Stellate и др.) уже имеют встроенные или очень легко подключаемые механизмы защиты от GraphQL-специфичных DDoS-атак.
Плохая новость: если вы до сих пор используете «голый» graphql-js/http/express без каких-либо защитных middleware — ваш API с очень высокой вероятностью уже уязвим к простым, но очень эффективным атакам стоимостью в несколько сотен запросов.
Вопрос-ответ
- Почему GraphQL-API считается более уязвимым к DDoS-атакам, чем классический REST? GraphQL позволяет клиенту в одном запросе указать произвольную структуру данных, включая вложенные связи. Из-за этого небольшой по объёму запрос (300–800 байт) может заставить сервер выполнить тысячи обращений к базе данных и сложные вычисления. В REST аналогичный результат обычно требует множества отдельных запросов, что само по себе ограничивает нагрузку. В GraphQL же вся нагрузка концентрируется в одном запросе, что делает атаки гораздо более эффективными по соотношению «объём трафика → потребляемые ресурсы».
- Что такое «глубокий запрос» и почему он опасен? Глубокий запрос — это GraphQL-запрос с очень большой вложенностью полей (15–30 уровней и более). На каждом уровне могут находиться связи «один-ко-многим» (компания → сотрудники → проекты → задачи → комментарии → автор → лайки и т.д.). Сервер вынужден рекурсивно подгружать данные, что приводит к сотням или тысячам запросов к базе за один GraphQL-запрос. Даже при оптимизированной базе такая глубина обычно вызывает резкий рост времени выполнения и потребления памяти/процессора.
- Сколько примерно уровней глубины считается уже опасным в 2025 году? Значения глубины больше 10–12 уровней уже считаются потенциально опасными для большинства публичных API. Консервативные команды устанавливают лимит 6–8, средний уровень риска — 9–11. Лимиты выше 15 практически не встречаются на продакшене и обычно свидетельствуют об отсутствии защиты от глубоких запросов.
- Что лучше: лимит глубины или лимит сложности запроса? Лимит сложности (query cost analysis) значительно эффективнее и современнее. Лимит глубины — это простой и быстрый способ защиты, который хорошо отсекает явные «глубокие» атаки, но плохо справляется с «широкими» запросами (много полей на одном уровне) и с использованием большого количества алиасов. Система стоимости запроса учитывает одновременно глубину, ширину, «тяжесть» каждого поля и количество запрашиваемых элементов в списках.
- Можно ли обойти лимит глубины с помощью алиасов? Да, это один из самых распространённых способов обхода. Многие реализации лимита глубины считают каждый уровень вложенности только один раз, даже если он запрошен через десятки или сотни алиасов. Поэтому злоумышленники часто используют 100–500 алиасов на одном уровне, чтобы обойти ограничение. По этой причине в 2025 году разумный набор защит обязательно включает отдельный лимит на количество алиасов — обычно 100–250 максимум.
- Зачем запрещать introspection анонимным пользователям? Introspection позволяет полностью прочитать схему: все типы, поля, аргументы, deprecated-поля и их описания. Это даёт атакующему подробную карту API — какие поля «дорогие», где находятся самые глубокие связи, какие поля можно использовать для атаки. Большинство серьёзных GraphQL-специфичных DDoS-атак последних лет начинались именно с запроса introspection для анализа схемы.
- Какой таймаут выполнения запроса считается адекватным? Для публичного API разумный диапазон — 2–5 секунд. Для авторизованных пользователей — 6–12 секунд. Для внутренних сервис-к-сервису запросов с жёсткой аутентификацией — до 20–30 секунд в исключительных случаях. Запросы, которые не укладываются в эти рамки, в большинстве случаев либо ошибочны, либо сделаны специально.
- Нужно ли делать разные лимиты для разных типов пользователей? Да, это стандартная практика. Типичная схема: анонимные/неавторизованные пользователи получают самые жёсткие лимиты; зарегистрированные — заметно более мягкие; платные/премиум-пользователи — ещё более высокие; внутренние сервисы и B2B-клиенты с API-ключами — самые высокие лимиты. Разные уровни доступа позволяют сбалансировать безопасность и удобство.
- Можно ли полностью полагаться на WAF для защиты GraphQL? Нет, этого недостаточно. Классические WAF (Cloudflare, Akamai, Imperva и др.) плохо понимают семантику GraphQL-запросов. Они могут блокировать слишком длинные строки или определённые ключевые слова, но почти не способны эффективно ограничивать глубину, сложность или стоимость запроса. WAF полезен как дополнительный слой, но не заменяет специализированную GraphQL-защиту.
- Что делать, если после внедрения лимита сложности легитимные запросы стали отклоняться? Это частая ситуация. Обычно решается тремя способами: 1) повысить лимит сложности для авторизованных пользователей; 2) выделить особо «тяжёлые» операции на отдельный эндпоинт или с особым заголовком; 3) разбить тяжёлые операции на несколько последовательных запросов (чаще всего это самый правильный и масштабируемый подход).
- Нужен ли отдельный лимит на количество элементов в connection (first/last)? Да, это важная мера. Даже при наличии системы подсчёта сложности часто устанавливают жёсткий верхний предел first/last в диапазоне 50–150 элементов. Без такого ограничения пользователь может указать first: 1000000, и сервер может попытаться обработать этот запрос, что приведёт к серьёзной перегрузке.
- Что такое batching attack в контексте GraphQL? Это атака, при которой в одном HTTP-запросе отправляется массив из десятков или сотен отдельных GraphQL-операций. Каждая операция обрабатывается независимо, но использует ресурсы одного соединения. Такой подход позволяет обойти многие виды rate limiting, которые считают количество запросов по HTTP-запросам, а не по количеству GraphQL-операций.
- Какой максимальный размер батча считается разумным в 2025 году? Для публичного API — 3–8 операций в одном батче. Для авторизованных пользователей — 10–25. Для внутренних интеграций — 30–60 в исключительных случаях. Батчи больше 60–80 операций практически никогда не бывают легитимным сценарием на продакшене.
- Стоит ли запрещать persisted queries для публичного API? Полностью запрещать не обязательно, но контроль нужен жёсткий. Если вы разрешаете клиентам регистрировать persisted queries, каждый новый запрос должен проходить проверку (глубина, стоимость, отсутствие опасных паттернов) перед сохранением. Без такой проверки persisted queries могут стать удобным способом хранения и многократного использования «убийственных» запросов.
- Можно ли защититься только лимитами по IP? В 2025 году — практически нет. Большинство серьёзных атак проводится через тысячи разных IP-адресов (ботнеты, residential proxies, облачные инстансы). Ограничение по IP полезно как грубый первый барьер, но без дополнительных лимитов по токену, user_id или устройству эффект минимален.
- Как сильно влияет наличие dataloader на устойчивость к атакам? Очень сильно помогает против N+1-проблем, сокращая количество запросов к базе в десятки и сотни раз. Однако dataloader не защищает от намеренно тяжёлых запросов. Злоумышленник всё равно может сформировать очень широкие и глубокие структуры, которые даже с dataloader останутся крайне дорогими по CPU и памяти.
- Что делать, если атака всё-таки началась и API «лежит»? Быстро выполнить: 1) включить экстренно жёсткие лимиты (depth 5, fields 100, complexity 150, timeout 2 сек); 2) полностью отключить introspection; 3) активировать агрессивный rate limit по IP (30–60 req/min); 4) если есть — включить circuit breaker (при >80% ошибок 429/500 временно отдавать 503 всем); 5) после стабилизации проанализировать логи и добавить правила блокировки конкретных сигнатур атакующих запросов.
- Есть ли смысл использовать CAPTCHA для GraphQL? Смысл ограниченный. CAPTCHA эффективна против автоматизированных браузерных атак, но почти бесполезна против серверных ботов, которые отправляют запросы напрямую по HTTP. В 2025 году CAPTCHA в GraphQL применяют редко и только в узких сценариях (регистрация, восстановление пароля, чувствительные мутации).
- Какие open-source библиотеки для защиты GraphQL сейчас самые популярные? Среди часто используемых в 2025 году: graphql-depth-limit, graphql-query-complexity, graphql-cost-analysis, envelop (с плагинами cost-limit, depth-limit, rate-limiter), graphql-shield с rules, Apollo Server с плагинами (operation-duration, response-cache + custom cost), graphql-java с встроенными complexity и depth.
- Можно ли сказать, что GraphQL в принципе нельзя безопасно использовать для публичного API? Нет, можно, но требуется серьёзная многоуровневая защита. В 2025 году десятки крупных публичных GraphQL API успешно работают под высокой нагрузкой (GitHub, Shopify, Atlassian, Contentful и др.). Главное — понимать, что «голый» graphql-js/http/express без защитных middleware крайне уязвим. При правильной настройке лимитов глубины, сложности, таймаутов и rate limiting GraphQL становится вполне безопасным для публичного использования.