مجوز دسترسی فقط یه group ID نیست
خلاصهٔ کاملتر
نویسنده تو وبلاگ خودش میگه تو یه سرویس شبیه فید اجتماعی که خانوادهش ازش استفاده میکنه، بعد از اینکه به یه گروه دسترسی پیدا کرده، تونسته پستهای همون گروه از ماهها و سالها قبل رو هم ببینه. بین اون دادهها اسم، چهره و تاریخ تولد بچهها بود و حتی اطلاعات کسایی که دیگه عضو سرویس نیستن. اسم شرکت رو عمداً نگفته، چون موضوع سرزنش یه وندور خاص نیست و مشکل هنوز در حال بررسیه.
به گفتهٔ نویسنده، رفتاری که دیده با یه اشتباه خیلی کوچیک قابل توضیحه، هرچند خودش تأکید میکنه پیادهسازی واقعی رو نمیدونه: شرط دسترسی، تاریخ انتشار پست رو با createdAt کاربر مقایسه میکرده، یعنی تاریخ ساخت حساب، نه تاریخ عضویت تو اون گروه. برای اولین گروهِ هر کاربر این دو تاریخ معمولاً یکیه، پس تستهای مسیر خوشبینانه هم قشنگ جواب میدن و باگ پنهون میمونه.
function canView(User $auth, Post $post): bool
{
return ($post->sharedWithGroup?->is($auth->group) ?? true)
&& $post->publishedAt->isAfter($auth->createdAt);
}نکتهٔ اصلی اینه که مجوز دسترسی معمولاً به یه رابطه وصله، نه به دو تا ID فعلی. کاربر فقط «عضو گروه ۴۲» نیست؛ یه جایی عضو شده، میتونه بره، میتونه گروه عوض کنه و حتی برگرده. پیشنهاد نویسنده اینه که همین تاریخچه بیاد تو مدل: یه کلاس Membership با joinedAt و leftAt، تا شرط دسترسی از روی خود رابطه حساب بشه نه از روی یه timestamp که فقط یه بار تصادفی با اون همخوانی داشته.
ولی نویسنده معتقده باگ authorization بخش ترسناک ماجرا نیست. ترسناک اینه که یه شرط خراب کافی بوده تا سالها دادهٔ حساس باز بشه؛ یعنی چندتا تصمیم دیگه از قبل شکست خورده بودن: نگهداری بیپایانِ داده، نبودن مرز بین «عضو فعلی گروه» و «هر چیزی که این گروه تا حالا دیده»، و نبودن پاکسازی بعد از ترک گروه یا سرویس. خودش اسم این رو میذاره defense in depth، این بار برای privacy.
بخش آخر مقاله دربارهٔ اطلاعرسانیه. مشکل سریع و محکم بسته شده، که به نظر نویسنده خوبه، ولی پیام بعدیِ شرکت ماجرا رو «مشکل فنی عکسها» توصیف کرده، در حالی که قضیه دسترسی به دادهٔ شخصی بوده. میگه لازم نیست سر root cause حدس بزنی، همونقدر که میدونی رو بگو: چی دیدیم، چی نمیدونیم، چی کار کردیم. به گفتهٔ اون، جایگزین کردن یه واقعیت ناراحتکننده با یه نسخهٔ قشنگتر، خودِ اطلاعرسانی رو تبدیل میکنه به بخشی از حادثه.
نکات کلیدی:
- createdAt کاربر تاریخ عضویتش تو گروه نیست؛ این اشتباه تو اولین گروه بیسروصدا درست کار میکنه و بعد از تغییر گروه خراب میشه.
- مدل پیشنهادی یه کلاس Membership با فیلدهای user، group، joinedAt و leftAt که دسترسی رو به خودِ رابطه گره میزنه.
- دادهٔ لو رفته شامل اسم، چهره و تاریخ تولد بچهها بود؛ تاریخ تولد رو مثل پسورد نمیتونی عوض کنی و اثرش ممکنه ۱۵ سال بعد پیدا بشه.
- data minimization یعنی دادهای که نداری لو نمیره؛ retention باید بخشی از مدل داده و رفتار محصول باشه نه یه کار پاکسازی که امیدواری یادت بمونه.
- هر گزینهٔ تنظیماتِ اضافه یه حالت جدیده که باید امنش کنی؛ پیشفرضهای حساس باید محدودکننده باشن و ساختن حالتهای خطرناک باید سخت باشه.




