فقدان یک بررسی امنیتی در یک نقطه پایانی (endpoint) مجموعه‌ای از نوع GET، به هر کسی که یک حساب کاربری معمولی در CoopCycle داشت اجازه داد تا دفترچه آدرس کامل تمام فروشگاه‌ها را در یک نمونه مشترک (shared instance) دریافت کند؛ این اتفاق باعث افشای نام‌ها، آدرس‌های خیابانی و کدهای پستی تعداد بی‌شماری از مشتریان شد. این نقص ظرف دو روز اصلاح شد و از کاربران خواسته شده است که به آخرین نسخه منتشر شده ارتقا یابند.

چگونه این نشت رخ داد

CoopCycle – یک پلتفرم لجستیک متن‌باز که توسط تعاونی‌های تحویل غذا استفاده می‌شود – API خود را با استفاده از فریم‌ورک PHP به نام API Platform تعریف می‌کند. در این فریم‌ورک، هر عملیات (مانند POST، GET و غیره) باید با یک عبارت امنیتی (security expression) همراه باشد؛ اگر این عبارت حذف شود، فریم‌ورک کد را بدون هیچ‌گونه بررسی مجوز (authorization check) اجرا می‌کند.

توسعه‌دهندگان درخواست POST را که لیست آدرس‌های یک فروشگاه را ایجاد یا به‌روزرسانی می‌کند، با عبارت استاندارد is_granted('edit', object) محافظت کرده بودند. این کار به درستی عمل می‌کند زیرا درخواست، یک موجودیت (entity) واحد از فروشگاه را هدف قرار می‌دهد و یک «object» مشخص برای ارزیابی در اختیار فریم‌ورک قرار می‌دهد.

اما درخواست GET که همان منبع را می‌خواند، یک مجموعه (collection) را هدف قرار می‌دهد: /api/stores/{id}/addresses. یک مجموعه فاقد یک object واحد است، بنابراین عبارت is_granted('edit', object) نمی‌تواند برای آن اعمال شود. از آنجایی که توسعه‌دهندگان خط مربوط به امنیت را نادیده گرفته بودند، فریم‌ورک داده‌های آدرس را به هر کاربر احراز هویت شده‌ای، بدون توجه به محدوده دسترسی مستاجر (tenancy)، ارائه می‌داد.

در یک نمونه مشترک CoopCycle، یک کاربر مخرب می‌توانست به سادگی با پیمایش در شناسه‌های (ID) فروشگاه‌ها و ارسال درخواست‌های GET به آن نقطه پایانی، آدرس‌های محل سکونت تمام مشتریان ذخیره شده در سیستم را استخراج (scrape) کند. برای این کار، هیچ امتیاز یا سطح دسترسی اضافه‌ای فراتر از یک حساب کاربری معمولی مورد نیاز نبود.

چرا این باگ پابرجا ماند

این مشکل صرفاً یک سهل‌انگاری ساده نبود. مدل امنیتی بیانی (declarative) در API Platform فاقد روشی مستقیم برای بیان این موضوع است که «کاربر باید متعلق به همان مستاجری باشد که هر object در آن مجموعه به آن تعلق دارد». خط کد مفقود شده دقیقاً در جایی قرار داشت که فریم‌ورک، فرآیند احراز مجوز را دشوار می‌کرد.

علاوه بر این، مجموعه تست (test suite) پروژه در واقع تأیید می‌کرد که دریافت پاسخ GET حاوی تمام آدرس‌ها، رفتار مورد انتظار است. به عبارت دیگر، تست‌های خودکار با موفقیت پاس می‌شدند زیرا فیکسچرها (fixtures) مورد استفاده در تست، اجازه دسترسی بین‌مستاجری (cross-tenant access) را می‌دادند و در واقع این آسیب‌پذیری را پنهان می‌کردند. در این مورد، یک مجموعه تست سبز (موفق)، حس امنیت کاذبی را ایجاد کرده بود.

چه کسانی سود می‌برند و چه کسانی ضرر می‌کنند

  • مشتریان: اطلاعات هویتی حساس (PII) آن‌ها – شامل نام کامل و آدرس محل سکونت – در اختیار هر کسی که در پلتفرم بود قرار گرفت. اگرچه داده‌ها به صورت عمومی منتشر نشد، اما این نقض امنیتی حریم خصوصی را در چندین تعاونی به خطر انداخت.
  • تعاونی‌های استفاده‌کننده از CoopCycle: اعتماد به توانایی پلتفرم در محافظت از داده‌های مستاجران متزلزل شد. هر تعاونی که هنوز ارتقا نیافته بود، با خطر تداوم افشای اطلاعات مواجه بود.
  • نگهدارندگان CoopCycle: پاسخ سریع آن‌ها – ارائه اصلاحیه ظرف دو روز و افزودن تست‌های رگرسیون – بازه زمانی سوءاستفاده را محدود کرد و مدیریت مسئولانه در پروژه‌های متن‌باز را نشان داد. با این حال، این حادثه نیاز به فرآیندهای بازبینی امنیتی دقیق‌تر، به‌ویژه در مورد تنظیمات پیش‌فرض مبتنی بر فریم‌ورک را برجسته کرد.

توسعه‌دهندگان و حسابرسان باید به دنبال چه باشند

  • عدم تقارن عملیات: اگر یک درخواست POST (یا هر عملیات تغییردهنده دیگری) در یک مسیر محافظت شده باشد اما درخواست GET متناظر با آن باز باشد، این عدم تقارن یک نشانه هشدار (red flag) است. وجود POST نشان‌دهنده قصد توسعه‌دهندگان برای محافظت از آن منبع است.
  • نقاط پایانی مجموعه (Collection endpoints): هر چیزی که به جای یک آیتم واحد، یک لیست را برمی‌گرداند، اغلب خارج از الگوهای امنیتی معمول قرار می‌گیرد. بررسی کنید که بررسی‌های احراز مجوز به‌طور صریح برای خواندن دسته‌ای (bulk reads) اضافه شده باشند.
  • واقع‌گرایانه بودن مجموعه تست: اطمینان حاصل کنید که فیکسچرها بازتاب‌دهنده مرزهای واقعی مستاجران هستند. تست‌هایی که با موفقیت عبور می‌کنند اما نشت داده‌های بین‌مستاجری را تأیید می‌کنند، یک نشانه هشدار هستند، نه چراغ سبز.

اصلاحیه و گام‌های بعدی

پس از گزارش این آسیب‌پذیری، تیم اصلی CoopCycle عبارت امنیتی مفقود شده را به عملیات مجموعه GET اضافه کرد و تست‌های رگرسیونی را معرفی نمود که جداسازی مستاجران (tenant isolation) را هم برای نقاط پایانی تک‌آیتمی و هم برای مجموعه‌ای اعمال می‌کنند. این اصلاحیه در نسخه بعدی نرم‌افزار عرضه شد.

کاربران CoopCycle باید:

  1. بررسی کنند که آیا از نسخه جدید نرم‌افزار استفاده می‌کنند یا خیر.
  2. هرگونه افزونه یا پلاگین سفارشی را که ممکن است شکاف‌های مشابه در سطح مجموعه ایجاد کند، بازبینی کنند.
  3. اسکن‌های امنیتی را با تمرکز بر عدم تقارن خواندن/نوشتن در تمام مسیرهای API مجدداً اجرا کنند.

نکته کلیدی

چارچوب‌هایی که امنیت را به صورت اعلامی تعریف می‌کنند، می‌توانند شکاف‌های خطرناکی را پنهان کنند؛ به‌ویژه زمانی که توسعه‌دهندگان به الگوهایی تکیه می‌کنند که تنها برای اشیاء منفرد کار می‌کنند. یک بررسی ساده — اینکه آیا بخش خواندن یک اندپوینت، همان محافظتِ بخش نوشتن را دارد یا خیر — می‌تواند دسته‌ای از نشت‌های داده‌ای بین‌مستاجری را آشکار کند که در غیر این صورت، پشت مجموعه‌تست‌های موفق پنهان می‌ماندند.