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

Як стався витік

CoopCycle — логістична платформа з відкритим вихідним кодом, яку використовують кооперативи з доставки їжі, — визначає свій API за допомогою PHP-фреймворку API Platform. У цьому фреймворку кожна операція (POST, GET тощо) має бути поєднана з виразом безпеки; якщо вираз пропущено, фреймворк виконує код без жодної перевірки авторизації.

Розробники захистили POST-запит, який створює або оновлює список адрес магазину, стандартним виразом is_granted('edit', object). Це працює тому, що запит націлений на одну конкретну сутність магазину, надаючи фреймворку чіткий «об'єкт» для оцінки.

GET-запит, який зчитує той самий ресурс, націлений на колекцію: /api/stores/{id}/addresses. Колекція не має єдиного об'єкта, тому той самий вираз is_granted('edit', object) застосувати неможливо. Оскільки розробники пропустили рядок безпеки, фреймворк надавав дані про адреси будь-якому автентифікованому користувачеві, незалежно від тенанта.

У спільному екземплярі CoopCycle зловмисник міг просто перебирати ID магазинів, надсилати GET-запити на кінцеву точку та збирати домашні адреси кожного клієнта, збереженого в системі. Для цього не було потрібно жодних додаткових привілеїв, окрім звичайного облікового запису.

Чому баг не було виявлено

Проблема не була простою помилкою через неуважність. Декларативна модель безпеки API Platform не має простого способу виразити те, що «користувач повинен належати до того ж тенанта, що й кожен об'єкт у колекції». Пропущений рядок коду знаходився саме там, де фреймворк робив авторизацію складною.

Ситуацію погіршило те, що набір тестів проєкту фактично стверджував, що GET-відповідь, яка містить усі адреси, є очікуваною поведінкою. Іншими словами, автоматизовані тести проходили успішно, оскільки фікстури (fixtures), що використовувалися під час тестування, дозволяли доступ між тенантами, фактично маскуючи вразливість. У цьому випадку «зелений» набір тестів створив хибне відчуття безпеки.

Хто виграв, а хто програв

  • Клієнти: Їхні персональні дані (PII) — повні імена та домашні адреси — були відкриті для будь-кого на платформі. Хоча дані не були опубліковані у відкритому доступі, цей витік порушив конфіденційність у багатьох кооперативах.
  • Кооперативи, що використовують CoopCycle: Довіра до здатності платформи захищати дані тенантів була підірвана. Будь-який кооператив, який ще не оновився, ризикував продовженням витоку даних.
  • Підтримувачі CoopCycle: Їхня швидка реакція — виправлення протягом двох днів та додавання регресійних тестів — обмежила вікно експлуатації вразливості та продемонструвала відповідальне управління open-source проєктом. Однак цей інцидент підкреслює потребу в суворіших процесах перевірки безпеки, особливо щодо налаштувань за замовчуванням, що визначаються фреймворком.

На що варто звернути увагу розробникам та аудиторам

  • Асиметрія операцій: Якщо POST-запит (або будь-яка операція, що змінює дані) на певному шляху захищений, а відповідний GET-запит є відкритим, така невідповідність є тривожним сигналом. POST-запит демонструє намір розробників захистити ресурс.
  • Кінцеві точки колекцій: Будь-що, що повертає список, а не один елемент, часто випадає з межі звичних патернів безпеки. Перевіряйте, чи додані явні перевірки авторизації для масового читання даних.
  • Реалістичність наборів тестів: Переконайтеся, що фікстури відображають реальні межі тенантів. Тест, який проходить успішно, але підтверджує витік даних між тенантами, є попереджувальним знаком, а не сигналом про успіх.

Виправлення та наступні кроки

Після повідомлення про вразливість основна команда CoopCycle додала відсутній вираз безпеки до операції GET-колекції та впровадила регресійні тести, які забезпечують ізоляцію тенантів як для окремих елементів, так і для кінцевих точок колекцій. Виправлення було випущено в наступній версії програмного забезпечення.

Користувачам CoopCycle слід:

  1. Переконатися, що вони використовують останню версію програмного забезпечення.
  2. Переглянути будь-які кастомні розширення або плагіни, які можуть створювати подібні прогалини на рівні колекцій.
  3. Повторно запустити сканування безпеки, зосередившись на асиметрії читання/запису на всіх маршрутах API.

Висновок

Фреймворки, що роблять безпеку декларативною, можуть приховувати небезпечні прогалини, коли розробники покладаються на патерни, які працюють лише для окремих об'єктів. Проста перевірка — чи має сторона читання ендпоінту такий самий захист, як і сторона запису? — може виявити цілий клас витоків між тенантами, які інакше залишалися б прихованими за «зеленими» наборами тестів.