Як протестувати безпеку GraphQL API?

GraphQL стала популярною технологією для сучасних застосунків, але вона також створює виклики у сфері безпеки, для вирішення яких багато підходів до тестування ніколи не були призначені.

Ефективне тестування безпеки вимагає глибокого розуміння того, як ці API працюють на практиці.

Чому GraphQL API створюють виклики для традиційних методів безпеки?

На відміну від REST API, котрий для кожного ресурсу має окрему URL, GraphQL API зазвичай відкриває лише одну кінцеву точку яка приймає безліч різних запитів та мутацій. Об’єктом тестування є не лише сама URL, а й схема, логіка резолверів (resolvers), що за нею стоїть, і правила авторизації, які застосовуються до кожного типу, поля та операції. На відміну від Invicti (на базі Acunetix та Netsparker), сканери DAST, які бачать graphql лише як одну кінцеву точку, можуть пропустити реальну складність, що прихована за ним.

Зловмисники можуть використовувати інтроспекцію, підказки полів або реконструкцію схеми, щоб скласти карту доступних типів, полів, запитів та мутацій. Щойно вони зрозуміють схему, вони зможуть протестувати її на наявність надмірно відкритих полів, небезпечного доступу до об’єктів, зловживання пакетними обробками (batching), надмірної складності запитів та вразливостей до ін’єкцій на рівні резолверів.

Тестування безпеки GraphQL API

Виявлення та аналіз схеми

Визначення доступних запитів, мутацій, підписок, типів, полів, аргументів та зв’язків за допомогою інтроспекції, файлів схеми, аналізу трафіку або реконструкції схеми.

Схема є основою тестування GraphQL API. Вона визначає, які операції існують, які вхідні дані вони приймають, які об’єкти повертають і як ці об’єкти пов’язані між собою. Якщо зловмисники зможуть отримати схему, вони можуть використати її як карту для пошуку конфіденційних полів, прихованого функціоналу, вразливих шляхів авторизації та ресурсомістких запитів.

Тестування безпеки має відповідати на кілька основних питань:

  • Чи може неавтентифікований користувач отримати деталі схеми? Чи може користувач із низьким рівнем привілеїв отримати деталі схеми, які мають бути внутрішніми?
  • Чи відкритий доступ до конфіденційних типів, застарілих полів, адміністративних мутацій або внутрішніх зв’язків об’єктів?
  • Чи розкриває схема поля, які не використовуються фронтендом, але все ще залишаються доступними?
  • Чи відповідає документація API поточній робочій схемі?

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

Зловживання інтроспекцією

Необхідно перевірити, чи увімкнена інтроспекція GraphQL API у продакшені, та чи залишаються доступними альтернативні шляхи витоку схеми.

Запит інтроспекції дозволяє GraphQL API описувати власну схему, зокрема доступні типи, поля, запити, мутації та підписки. Хоча це корисно під час розробки, необмежена інтроспекція у продакшені може надати зловмисникам «дорожню карту» застосунку.

Тестування має визначити, чи інтроспекція вимкнена, або належним чином обмежена. Якщо стандартна інтроспекція заблокована, потрібно перевірити, чи підказки щодо полів та розгорнуті повідомлення про помилки все ще не розкривають деталі схеми. Деякі реалізації повертають підказки, наприклад «Ви мали на увазі електронну пошту клієнта?», які можуть допомогти зловмисникам відтворити схему, навіть коли інтроспекція недоступна.

Експлуатація запитів GraphQL API

Маніпулювання запитами для тестування на надмірне вилучення даних, зловживання вкладеними запитами, атаки на основі складності запитів, атаки з використанням пакетування (batching attacks) та несанкціонований доступ до даних.

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

Тестування має охоплювати сценарії як розкриття даних, так і вичерпання ресурсів. Для перевірки на розкриття даних потрібно спробувати надіслати запит на отримання конфіденційних полів через різні зв’язки об’єктів та шляхи запитів. Щодо зловживання ресурсами, слід перевірити, чи можуть глибоко вкладені запити, повторювані фрагменти, циклічні зв’язки або комбінації ресурсомістких резолверів споживати надмірну кількість процесорного часу (CPU), пам’яті, ресурсів бази даних або викликів низхідних сервісів.

До важливих засобів контролю, які необхідно перевірити, належать:

  • Обмеження глибини (depth limiting) для запобігання виконанню глибоко вкладених запитів.
  • Аналіз складності запитів для врахування ресурсомістких полів та особливостей роботи резолверів.
  • Застосування тайм-аутів для повільних або ресурсомістких операцій.
  • Обмеження частоти запитів, яке застосовується саме до операцій GraphQL, а не лише до HTTP-запитів загалом.
  • Використання збережених запитів там, де це доречно, особливо для робочого API з високим рівнем ризику.

Збережені запити можуть зменшити ризики вразливості, дозволяючи виконання лише попередньо затверджених операцій замість довільних запитів, надісланих клієнтом. Вони найбільш доцільні у суворо контрольованих робочих середовищах, де обмеження гнучкості запитів є прийнятним. Хоча збережені запити не замінюють механізми авторизації чи захист самої схеми, вони здатні значно зменшити можливості для розвідки схеми та зловживань нею.

Атаки з використанням пакетних запитів (Batching attacks)

Необхідно перевірити, чи можна зловживати пакетними запитами (batching) GraphQL. Такі запити можуть використовуватися для обходу обмежень частоти запитів, перебору облікових даних або перебирання ідентифікаторів. Пакетна обробка в GraphQL дозволяє клієнту надсилати кілька операцій в одному HTTP-запиті. Це може підвищити ефективність для легітимних клієнтів. Водночас така можливість здатна нівелювати механізми безпеки, які підраховують лише HTTP-запити, а не окремі операції. Наприклад, для мутації входу може діяти обмеження частоти на рівні HTTP-запитів. Однак система все одно може дозволити сотні спроб авторизації, якщо ці спроби об’єднані в один пакет.

Під час тестування слід перевірити, чи приймає API пакетні запити або мутації, і як поводяться засоби контролю безпеки у разі одночасного надсилання кількох операцій. Потрібно звернути особливу увагу на операції автентифікації, скидання пароля, обробки запрошень і купонів, а також на операції пошуку та вибірки об’єктів. Вони є типовими мішенями для атак brute-force та перебирання ідентифікаторів.

Ефективні засоби захисту повинні застосовувати обмеження на рівні окремих операцій, а не лише HTTP-запитів. Перевірка, системи моніторингу, логування, обмеження частоти, політики блокування облікових записів та виявлення аномалій здатні розпізнавати окремі операції всередині пакета. Якщо застосунок дозволяє пакетну обробку, він має застосовувати суворі ліміти щодо розміру пакета, кількості операцій, вартості їх виконання та мутацій, пов’язаних з автентифікацією.

Тестування авторизації та контроль доступу

Необхідно перевірити, чи можуть користувачі отримувати доступ лише до тих даних та операцій, які дозволені їхньою роллю, правом власності на об’єкт, тенантом та бізнес контекстом.

Авторизація у GraphQL API є складною, оскільки засоби контролю доступу може бути необхідно застосовувати на рівні операцій, об’єктів, полів та резолверів. Захисту кінцевих точок graphql API недостатньо. Користувачу може бути дозволено виконати запит, але він не обов’язково має бачити кожне поле, яке цей запит повертає.

Тестування має охоплювати порушення авторизації на рівні об’єктів (BOLA), небезпечні прямі посилання на об’єкти (IDOR), обхід авторизації на рівні полів та порушення ізоляції тенантів. Слід використовувати кілька облікових записів із різними ролями, дозволами, організаціями та правами власності. Потім потрібно перевірити, чи можуть ідентифікатори, вкладені зв’язки, фільтри, псевдоніми та альтернативні шляхи запитів розкрити дані поза цими межами.

Тестування на рівні полів заслуговує на особливу увагу. Доступ до одного й того ж конфіденційного поля може бути можливим через кілька шляхів. Наприклад, застосунок може надійно приховувати поля заробітної плати, номери соціального страхування (SSN), ключі API та внутрішні нотатки в одному запиті. Однак ці дані можуть розкриватися в іншому місці схеми. Витік може відбуватися через вкладені зв’язки співробітника, акаунту, організації або журналу аудиту. Засоби контролю доступу повинні діяти на всіх шляхах, а не лише в очевидних операціях, які використовує фронтенд.

Тестування авторизації також має охоплювати мутації. Слід переконатися, що користувачі не можуть створювати, оновлювати, видаляти, затверджувати, передавати, надсилати запрошення або призначати ресурси поза межами своєї ролі чи тенанта. У GraphQL API одна мутація може запускати кілька дій на бекенді, тому слід тестувати як відповідь, так і відповідні зміни стану.

Тестування також має охоплювати стан перегонів (race conditions) та вразливості авторизації типу «перевірка-потім-дія» (check-then-act). Одночасні мутації іноді можуть обходити бізнес правила, які здаються безпечними під час ізольованого тестування, особливо коли йдеться про перевірку права власності, перевірку балансу або робочі процеси затвердження.

Тестування підписок GraphQL

Тестування підписок GraphQL API на наявність ризиків, пов’язаних з авторизацією, розкриттям даних, обробкою з’єднань та відмовою в обслуговуванні (DoS).

Підписки дозволяють клієнтам отримувати оновлення в режимі реального часу через постійне з’єднання, зазвичай з використанням WebSockets. Їх часто тестують менш ретельно, ніж запити та мутації, оскільки вони не є частиною стандартного потоку «запит-відповідь», але вони можуть розкривати конфіденційні події та створювати специфічні експлуатаційні ризики.

Тестування безпеки має підтвердити, що підписки вимагають належної автентифікації під час встановлення з’єднання та авторизації під час ініціалізації підписки. Також слід перевірити, чи виконується повторна перевірка авторизації, коли змінюються дозволи користувача, закінчується термін дії токенів, вимикаються облікові записи або оновлюється членство в тенанті.

Тестувальники повинні перевіряти наявність розкриття потоку подій (event-stream exposure) між різними тенантами або ролями та переконатися, що користувачі не можуть підписатися на оновлення іншого клієнта шляхом маніпулювання ідентифікаторами або фільтрами. Також слід перевіряти засоби контролю використання ресурсів. До них належать обмеження кількості з’єднань, тайм-аути неактивності (idle timeouts) та обмеження розміру повідомлень. Таке тестування допомагає знизити ризик відмови в обслуговуванні.

Тестування GraphQL API на вразливості до ін’єкцій

Перевірка на наявність вразливостей до ін’єкцій в аргументах запитів, змінних, вхідних даних резолверів та викликах бекенд сервісів.

GraphQL API сам по собі не є мовою запитів до баз даних, але резолвери часто викликають бази даних, пошукові системи, інструменти командного рядка, внутрішні API, черги повідомлень або хмарні сервіси. Якщо вхідні дані резолверів не проходять валідацію та не обробляються безпечно, зловмисники можуть ініціювати SQL-ін’єкцію, NoSQL-ін’єкцію, ін’єкцію команд, LDAP-ін’єкцію, підробку запиту з боку сервера (SSRF) або небезпечну десеріалізацію через операції GraphQL API.

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

До корисних напрямків тестування належать:

  • Рядкові аргументи, що використовуються у фільтрах, пошуку, сортуванні або вибірці об’єктів (object lookup).
  • Числові аргументи, що використовуються для лімітів, зсувів, цін, кількості або ідентифікаторів.
  • Значення переліків (Enum) та варіанти за замовчуванням у логіці резолверів.
  • JSON-подібні кастомні скаляри (custom scalars).
  • Завантаження файлів.
  • URL-адреси, шляхи та значення зворотних викликів, що передаються до бекенд сервісів.

Мета полягає не лише в тому, щоб перевірити, чи повертає рівень GraphQL API помилку. Тестувальники повинні спостерігати за поведінкою бекенду там, де це можливо. Особливу увагу слід звертати на помилки бази даних і відмінності в часі виконання запитів. Також необхідно відстежувати out-of-band зворотні виклики, несподівані зміни стану та непослідовну валідацію в різних резолверах.

Висновок

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

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

Якщо ви бажаєте автоматично та точно тестувати GraphQL API на наявність вразливостей, ви можете безкоштовно спробувати рішення Invicti (на базі Acunetix та Netsparker). Для цього, будь ласка, залиште свої контактні дані нижче, і ми з вами зв’яжемося:

Запит на безкоштовне тестування Invicti

Підписатися на новини