Отсутствие проверки безопасности в эндпоинте GET-запроса для коллекций позволяло любому пользователю с базовым аккаунтом CoopCycle выгрузить полную адресную книгу всех магазинов в общем экземпляре, раскрывая имена, уличные адреса и почтовые индексы бесчисленного количества клиентов. Уязвимость была устранена в течение двух дней, и пользователям настоятельно рекомендуется обновиться до последней выпущенной версии.
Как произошла утечка
CoopCycle — логистическая платформа с открытым исходным кодом, используемая продовольственными кооперативами, — определяет свой API с помощью PHP-фреймворка API Platform. В этом фреймворке каждая операция (POST, GET и т. д.) должна сопровождаться выражением безопасности (security expression); если выражение пропущено, фреймворк выполняет код без какой-либо проверки авторизации.
Разработчики защитили POST-запрос, который создает или обновляет список адресов магазина, стандартным выражением is_granted('edit', object). Это работает, так как запрос нацелен на одну конкретную сущность магазина, предоставляя фреймворку определенный «объект» для оценки.
GET-запрос, который считывает тот же ресурс, нацелен на коллекцию: /api/stores/{id}/addresses. У коллекции нет одного конкретного объекта, поэтому к ней нельзя применить то же выражение is_granted('edit', object). Поскольку разработчики не добавили строку безопасности, фреймворк предоставлял данные об адресах любому аутентифицированному пользователю, независимо от принадлежности к арендатору (tenancy).
В общем экземпляре CoopCycle злоумышленник мог просто перебирать ID магазинов, отправлять GET-запросы к эндпоинту и собирать домашние адреса каждого клиента, хранящегося в системе. Для этого не требовалось никаких дополнительных привилегий, кроме обычной учетной записи.
Почему баг не был обнаружен
Проблема не была простой оплошностью. В декларативной модели безопасности API Platform отсутствует простой способ выразить условие: «пользователь должен принадлежать к тому же арендатору, что и каждый объект в коллекции». Пропущенная строка кода находилась именно там, где фреймворк делает авторизацию затруднительной.
Ситуацию усугубляло то, что набор тестов проекта фактически подтверждал, что GET-ответ, содержащий все адреса, является ожидаемым поведением. Другими словами, автоматизированные тесты проходили успешно, потому что фикстуры, используемые при тестировании, допускали доступ между арендаторами (cross-tenant access), фактически маскируя уязвимость. В данном случае «зеленый» набор тестов создал ложное чувство безопасности.
Кто выиграл, а кто проиграл
- Клиенты: Их персональные данные (PII) — полные имена и домашние адреса — стали доступны любому пользователю платформы. Несмотря на то, что данные не были опубликованы в открытом доступе, утечка нарушила конфиденциальность во многих кооперативах.
- Кооперативы, использующие CoopCycle: Доверие к способности платформы защищать данные арендаторов было подорвано. Любой кооператив, который еще не обновился, подвергался риску дальнейшей утечки.
- Мейнтейнеры CoopCycle: Их быстрая реакция — выпуск патча в течение двух дней и добавление регрессионных тестов — ограничила окно для эксплуатации уязвимости и продемонстрировала ответственное управление open-source проектом. Однако инцидент подчеркивает необходимость более строгого процесса проверки безопасности, особенно в отношении настроек по умолчанию, определяемых фреймворком.
На что следует обратить внимание разработчикам и аудиторам
- Асимметрия операций: Если путь (path) защищен для POST (или любой другой мутирующей операции), но соответствующий GET-запрос открыт, это тревожный сигнал. Наличие защиты в POST-запросе указывает на намерение разработчиков защитить ресурс.
- Эндпоинты коллекций: Все, что возвращает список, а не один элемент, часто выпадает из привычных паттернов безопасности. Убедитесь, что проверки авторизации явно добавлены для массового чтения данных.
- Реалистичность набора тестов: Убедитесь, что фикстуры отражают реальные границы арендаторов. Проходящий тест, который подтверждает утечку данных между арендаторами, — это предупреждающий знак, а не сигнал о том, что всё в порядке.
Исправление и следующие шаги
После сообщения об уязвимости основная команда CoopCycle добавила недостающее выражение безопасности для операции GET-коллекции и внедрила регрессионные тесты, обеспечивающие изоляцию арендаторов как для одиночных элементов, так и для эндпоинтов коллекций. Патч был включен в последующую версию программного обеспечения.
Пользователям CoopCycle следует:
- Убедиться, что они используют последнюю версию программного обеспечения.
- Проверить любые пользовательские расширения или плагины, которые могут вносить подобные пробелы на уровне коллекций.
- Повторно провести сканирование безопасности, уделяя особое внимание асимметрии чтения/записи на всех маршрутах API.
Вывод
Фреймворки, реализующие декларативный подход к безопасности, могут скрывать опасные уязвимости, когда разработчики полагаются на паттерны, работающие только для одиночных объектов. Простая проверка — есть ли у стороны чтения эндпоинта та же защита, что и у стороны записи? — может выявить целый класс утечек данных между тенантами, которые в противном случае остались бы незамеченными за «зелеными» наборами тестов.
