Повернутися до блогу
API Security4.07.2026

Безпека API GraphQL: інтроспекція, DoS, BOLA та укріплення резолверів

GraphQL замінює десятки REST-ендпоінтів єдиною гнучкою поверхнею запитів. Саме ця гнучкість ламає припущення безпеки, які команди переносять з REST. Один POST на /graphql може обходити довільні графи об'єктів, запитувати вкладені зв'язки та пакувати сотні операцій в один запит. Якщо авторизація, rate-limiting і контроль вартості проєктувалися по ендпоінтах, тут вони не працюють. Цей матеріал розбирає головні специфічні для GraphQL ризики та серверні заходи, що реально їх знижують.

Витік інтроспекції

GraphQL самоописовий. Один запит інтроспекції __schema повертає кожен тип, поле, аргумент, мутацію та застаріле поле. Для атакувальника це безкоштовна й достовірна карта всієї поверхні атаки — включно з внутрішніми адміністративними мутаціями та полями, які ви вважали прихованими.

Інтроспекція — легітимний інструмент розробника, але в проді вона віддає розвідку будь-кому. Вимкніть її у продакшн-збірках (наприклад introspection: false в Apollo Server) і вимкніть IDE Playground/GraphiQL у публічних розгортаннях. Пам'ятайте: вимкнення інтроспекції — це defense-in-depth, а не авторизація — інструменти на кшталт Clairvoyance відновлюють схему за підказками полів, тож вимкніть і повідомлення-підказки та ніколи не покладайтеся на таємність схеми як межу безпеки.

Глибина та складність запитів: неавтентифікований DoS

Оскільки форму запиту обирає клієнт, він може створювати глибоко вкладені циклічні запити, що вибухають роботою сервера. Якщо в Author є posts, а в Post є author, атакувальник рекурсивно спускається author→posts→author→posts на довільну глибину, спричиняючи експоненційне виконання резолверів і навантаження на БД з одного невеликого запиту. Це відповідає OWASP API4:2023 Unrestricted Resource Consumption і є класичним асиметричним DoS.

Застосовуйте пошарово:

  • Обмеження глибини — відхиляйте запити вище фіксованої вкладеності (наприклад graphql-depth-limit 7–10).
  • Аналіз складності — призначте вартість кожному полю і відхиляйте запити понад бюджет до виконання (graphql-cost-analysis, graphql-query-complexity).
  • Ліміти пагінації — примусово обмежуйте first/last; ніколи не допускайте безмежних списків.
  • Тайм-аути та ліміти кількості — обмежуйте час виконання й число повернутих вузлів.
  • Persisted queries — дозволяйте лише затверджений список документів запитів у проді, повністю усуваючи довільні форми.

Зловживання батчингом

GraphQL дозволяє надіслати масив операцій в одному HTTP-запиті, а аліасинг дозволяє клієнту повторити одне поле багато разів під різними іменами. Обидва обходять наївний rate-limiting за запитами. Один запит з 1000 аліасованих мутацій login обнуляє захист від перебору:

  • mutation { a: login(pw:"1"){token} b: login(pw:"2"){token} ... }

Обмежуйте число операцій на запит, число аліасів для чутливих полів і застосовуйте rate-limiting за вартістю операцій, а не за числом HTTP-запитів. Застосовуйте об'єктний тротлінг до автентифікації та інших схильних до зловживань мутацій.

BOLA / авторизація на рівні об'єкта в резолверах

Broken Object Level Authorization (OWASP API1:2023) — найруйнівніша й найчастіша вразливість GraphQL. Запит { invoice(id: "1042") { total, customer { email } } } поверне рахунок чужого орендаря, якщо резолвер вибирає за ID без перевірки власності. GraphQL погіршує це, бо авторизацію треба застосовувати в кожному резолвері на кожному шляху — поле, досяжне через три різні запити, вимагає перевірки в усіх трьох.

Не авторизуйте на рівні HTTP. Застосовуйте авторизацію на рівні поля та об'єкта всередині резолверів або виділеного шару авторизації: перевіряйте, що автентифікований суб'єкт має доступ до конкретного екземпляра об'єкта, а не лише до типу. Переносьте ідентичність у контексті та надавайте перевагу рушію політик (graphql-shield, OSO або явні guard-и), щоб перевірки були централізовані й тестовані. Вважайте кожне поле безпосередньо досяжним і за замовчуванням відмовляйте.

Ін'єкції через резолвери

GraphQL нічого не санітизує — він передає аргументи прямо в резолвери, які часто будують SQL, NoSQL або команди ОС. SQL-ін'єкція (CWE-89), NoSQL-ін'єкція та SSRF живуть у коді резолверів. Оскільки мова запитів виглядає структурною, розробники помилково вважають ввід безпечним. Завжди використовуйте параметризовані запити, валідуйте кастомні скаляри та вважайте кожен аргумент недовіреним. Стережіться аргументів filter/where, що передають сирі об'єкти операторів у запит Mongo/ORM.

Помилки та розкриття інформації

Багатослівні помилки GraphQL розкривають стек-трейси, повідомлення драйвера БД і внутрішні шляхи полів. Маскуйте помилки в проді, логуйте деталі на сервері та повертайте клієнтам загальні повідомлення. Разом із вимкненою інтроспекцією це позбавляє атакувальника циклу розвідки.

Практичний чек-лист укріплення

  • Вимкніть інтроспекцію та IDE у проді; вимкніть підказки полів.
  • Застосовуйте ліміти глибини та складності й пагінації до виконання.
  • Обмежте батчинг і аліаси; rate-limiting за вартістю, а не за числом запитів.
  • Авторизація на рівні об'єкта в кожному резолвері, відмова за замовчуванням, централізована політика.
  • Параметризовані запити та сувора валідація вводу в резолверах.
  • Маскуйте помилки та розгляньте persisted/allow-listed queries для найсильнішої позиції.

GraphQL не є небезпечним за своєю природою, але переносить межу безпеки з ендпоінта в граф резолверів. Змоделюйте цей граф, тестуйте кожен досяжний шлях на авторизацію та вартість і ставтеся до схеми як до живої поверхні атаки, а не документації. Оцінюючи API GraphQL, ми зіставляємо знахідки з CVSS і OWASP API Security Top 10, щоб пріоритизувати усунення за реальним бізнес-впливом.

graphqlapi-securityowasp-apidosbolaauthorization