GraphQL
Уязвимости GraphQL, как правило, возникают из-за ошибок реализации и проектирования. Например, функция интроспекции может быть оставлена включенной, что позволит атакующим опрашивать API, чтобы узнать сведения о его схеме.
Атаки на GraphQL обычно представляют собой вредоносные запросы, позволяющие атакующему получить данные или выполнить несанкционированные действия. Эти атаки могут иметь тяжелые последствия, особенно если пользователю удается получить права администратора путем манипуляций с запросами или выполнения эксплойта CSRF. Уязвимые GraphQL API также могут приводить к утечкам информации.
В этом разделе вы узнаете как тестировать GraphQL. Не переживайте, если вы не знакомы с GraphQL — по ходу дела мы рассмотрим необходимые детали.

Поиск конечных точек GraphQL
Прежде чем тестировать GraphQL API, сначала необходимо найти его конечную точку. Поскольку GraphQL API используют одну и ту же конечную точку для всех запросов, это критически важная информация.
Универсальные запросы
Если отправить query{__typename} на любой GraphQL-эндпоинт, в ответе где-то будет присутствовать строка {"data": {"__typename": "query"}}. Это называется универсальным запросом и является полезным инструментом для проверки, соответствует ли URL службе GraphQL.
Запрос работает, потому что у каждого GraphQL-эндпоинта есть зарезервированное поле __typename, которое возвращает тип запрошенного объекта в виде строки.
Распространенные имена конечных точек
Сервисы GraphQL часто используют похожие суффиксы конечных точек. При тестировании на наличие GraphQL-эндпоинтов следует попытаться отправить универсальные запросы по следующим адресам:
/graphql/api/api/graphql/graphql/api/graphql/graphql
Если эти типовые конечные точки не возвращают GraphQL-ответ, можно также попробовать добавить к пути /v1.
Методы запросов
Следующим шагом в поиске GraphQL-эндпоинтов является тестирование с использованием разных методов запроса.
Рекомендуется, чтобы в продакшене GraphQL-эндпоинты принимали только POST-запросы с типом содержимого application/json, поскольку это помогает защититься от уязвимостей CSRF. Однако некоторые конечные точки могут принимать альтернативные методы, такие как GET-запросы или POST-запросы с типом содержимого x-www-form-urlencoded.
Если вам не удается найти GraphQL-эндпоинт, отправляя POST-запросы на типовые пути, попробуйте переотправить универсальный запрос, используя альтернативные методы HTTP.
Первичное тестирование
После того как вы обнаружили конечную точку, можно отправить несколько тестовых запросов, чтобы лучше понять, как она работает. Если конечная точка обслуживает веб-сайт, попробуйте изучить веб-интерфейс в браузере Burp и используйте историю HTTP, чтобы проанализировать отправляемые запросы.
Эксплуатация невалидируемых аргументов
На этом этапе можно начинать искать уязвимости. Хорошая отправная точка — тестирование аргументов запросов.
Если API использует аргументы для прямого доступа к объектам, это может привести к уязвимостям контроля доступа. Пользователь потенциально может получить доступ к информации, к которой не должен иметь доступа, просто передав аргумент, соответствующий этой информации. Это иногда называют небезопасной прямой ссылкой на объект (IDOR).
Например, следующий запрос запрашивает список товаров для интернет-магазина:
Возвращенный список продуктов содержит только перечисленные продукты.
Из этой информации можно сделать следующие выводы:
Товарам присваиваются последовательные идентификаторы.
В списке отсутствует товар с ID 3, возможно, потому что он снят с публикации.
Запросив ID отсутствующего товара, мы можем получить его сведения, даже если он не отображается в магазине и не был возвращен исходным запросом списка товаров.
Выявление сведений о схеме
Следующим шагом тестирования API является сбор сведений о базовой схеме. Лучший способ сделать это — использовать запросы интроспекции. Интроспекция — встроенная функция GraphQL, позволяющая запрашивать у сервера информацию о схеме.
Интроспекция помогает понять, как можно взаимодействовать с GraphQL API. Она также может раскрывать потенциально чувствительные данные, например поля описаний.
Использование интроспекции
Чтобы с помощью интроспекции получить сведения о схеме, запросите поле __schema. Это поле доступно в корневом типе всех запросов.
Как и в обычных запросах, вы можете указать поля и структуру ответа, который хотите получить при выполнении запроса интроспекции. Например, вы можете захотеть, чтобы ответ содержал только названия доступных мутаций.
Проверка доступности интроспекции
В продакшене рекомендуется отключать интроспекцию, но этому совету следуют не всегда. Вы можете проверить доступность интроспекции с помощью следующего простого запроса. Если интроспекция включена, в ответе будут возвращены названия всех доступных запросов.
Запуск полной интроспекции
Следующим шагом является запуск полного запроса интроспекции к конечной точке, чтобы получить максимально возможный объем сведений о базовой схеме.
Приведенный ниже пример запроса возвращает полные сведения обо всех запросах, мутациях, подписках, типах и фрагментах.
Визуализация результатов интроспекции
Ответы на запросы интроспекции могут быть очень информативными, но часто они длинные и трудны для анализа.
Вы можете проще просматривать связи между сущностями схемы, используя GraphQL visualizer. Это онлайн-инструмент, который принимает результаты запроса интроспекции и создает визуальное представление возвращенных данных, включая связи между операциями и типами.
Предложения (suggestions)
Даже если интроспекция полностью отключена, иногда можно использовать «предложения», чтобы получить сведения о структуре API.
Предложения — это функция платформы Apollo GraphQL, при которой сервер может предлагать исправления запросов в сообщениях об ошибках. Они обычно используются, когда запрос слегка некорректен, но распознается (например: There is no entry for 'productInfo'. Did you mean 'productInformation' instead?).
Из этого можно почерпнуть полезную информацию, поскольку ответ фактически раскрывает валидные части схемы.
Clairvoyance — это инструмент, который использует предложения для автоматического восстановления всей или части схемы GraphQL, даже когда интроспекция отключена. Это значительно сокращает время на сбор сведений из ответов с подсказками.
Нельзя напрямую отключить предложения в Apollo. См. эту тему на GitHub для обходного решения.
Обход защит от интроспекции GraphQL
Если вы не можете выполнить запросы интроспекции для тестируемого API, попробуйте вставить специальный символ после ключевого слова __schema.
Когда разработчики отключают интроспекцию, они могут использовать регулярное выражение (regex), чтобы исключать ключевое слово __schema в запросах. Попробуйте символы вроде пробелов, переводов строк и запятых — GraphQL их игнорирует, но некорректные regex — нет.
Таким образом, если разработчик исключил только __schema{, то приведенный ниже запрос интроспекции не будет исключен.
Если это не сработает, попробуйте выполнить проверку другим методом запроса, так как интроспекция может быть отключена только для POST. Попробуйте GET-запрос или POST-запрос с типом содержимого x-www-form-urlencoded.
Ниже приведен пример запроса проверки интроспекции, отправленного через GET с параметрами в кодировке URL.
Обход ограничения скорости с помощью алиасов
Обычно объекты GraphQL не могут содержать несколько свойств с одинаковым именем. Алиасы позволяют обойти это ограничение, явно задавая имена свойств, которые вы хотите получить от API. С их помощью можно вернуть несколько экземпляров одного и того же типа объекта в одном запросе.
Хотя алиасы предназначены для сокращения числа вызовов API, их также можно использовать для брутфорса GraphQL-эндпоинта.
Во многих конечных точках настроен какой-то ограничитель скорости, предотвращающий перебор. Некоторые ограничители работают, основываясь на количестве полученных HTTP-запросов, а не на числе операций, выполненных в эндпоинте. Поскольку алиасы фактически позволяют отправлять несколько запросов в одном HTTP-сообщении, они могут обойти это ограничение.
Упрощенный пример ниже показывает серию алиасных запросов, проверяющих валидность скидочных кодов магазина. Эта операция потенциально может обойти ограничение скорости, так как это один HTTP-запрос, хотя он может проверить очень большое количество кодов за раз.
GraphQL CSRF
CSRF позволяет атакующему заставить пользователей выполнять действия, которые они не намеревались выполнять. Это делается путем создания вредоносного веб-сайта, который выполняет запрос к уязвимому приложению.
GraphQL может использоваться как вектор для атак CSRF, при котором злоумышленник создает эксплойт, заставляющий браузер жертвы отправить вредоносный запрос от имени жертвы.
Как возникает CSRF через GraphQL?
Уязвимости CSRF могут возникать, когда GraphQL-эндпоинт не проверяет тип содержимого (content type) получаемых запросов и не использует CSRF-токены.
POST-запросы с типом содержимого application/json защищены от подделки, при условии что тип содержимого валидируется. В этом случае злоумышленник не сможет заставить браузер жертвы отправить такой запрос даже при посещении жертвой вредоносного сайта.
Однако альтернативные методы, такие как GET, или любой запрос с типом содержимого x-www-form-urlencoded, могут быть отправлены браузером, и поэтому могут оставлять пользователей уязвимыми, если эндпоинт принимает такие запросы. В этом случае злоумышленники могут сформировать эксплойты для отправки вредоносных запросов к API. Шаги по конструированию и доставке CSRF эксплойта на основе GraphQL такие же, как и для «обычных» CSRF. Подробнее об этом процессе см. раздел Cross-Site Request Forgery (CSRF).
Предотвращение атак на GraphQL
Чтобы предотвратить многие типичные атаки на GraphQL, при выводе API в продакшен выполните следующие шаги:
Если ваш API не предназначен для широкой публики, отключите на нем интроспекцию. Это затруднит злоумышленнику получение информации о работе API и снизит риск нежелательного раскрытия информации. Сведения о том, как отключить интроспекцию на платформе Apollo GraphQL, см. в этой записи в блоге.
Если ваш API предназначен для широкой публики, скорее всего, вам придется оставить интроспекцию включенной. Однако следует пересмотреть схему API, чтобы убедиться, что она не раскрывает нежелательные поля для общего доступа.
Убедитесь, что «предложения» (suggestions) отключены. Это не позволит злоумышленникам использовать Clairvoyance или аналогичные инструменты для сбора сведений о базовой схеме. Нельзя напрямую отключить предложения в Apollo. См. эту тему на GitHub для обходного решения.
Убедитесь, что схема вашего API не раскрывает никаких приватных полей пользователей, таких как адреса электронной почты или идентификаторы пользователей.
Предотвращение брутфорса GraphQL
Иногда возможно обойти стандартное ограничение скорости при использовании GraphQL API. С учетом этого есть архитектурные меры, которые вы можете предпринять для защиты API от атак перебора. Обычно это включает ограничение сложности принимаемых запросов и снижение возможностей для проведения DoS атак.
Чтобы защититься от атак перебора:
Ограничьте глубину запросов вашего API. «Глубина запроса» — это количество уровней вложенности внутри запроса. Сильно вложенные запросы могут существенно влиять на производительность и потенциально создавать возможности для DoS-атак. Ограничив глубину, вы снижаете вероятность этого.
Настройте лимиты операций. Они позволяют задать максимальное количество уникальных полей, алиасов и корневых полей, которые ваш API может принять.
Настройте максимальный размер запроса в байтах.
Рассмотрите внедрение анализа стоимости в вашем API. Анализ стоимости — процесс, при котором библиотека определяет ресурсную стоимость выполнения запросов по мере их получения. Если запрос слишком ресурсоемкий, API отклоняет его.
Предотвращение CSRF через GraphQL
Чтобы защититься от уязвимостей CSRF через GraphQL, убедитесь в следующем при проектировании API:
Ваш API принимает запросы только как POST с JSON-кодировкой.
API проверяет соответствие предоставленного содержимого заявленному типу содержимого.
В API реализован надежный механизм CSRF-токенов.
Last updated