SSRF تو لاراول؛ وقتی یه خط Http::get کافیه
خلاصهٔ کاملتر
نویسنده میگه تقریباً هر اپلیکیشنی یه جا URLی که کاربر داده رو fetch میکنه: وبهوک، پیشنمایش لینک، ایمپورت آواتار، رندر PDF. کدش معمولاً یه خطه و دقیقاً به همین دلیل هیچوقت جدی ریویو نمیشه. قانون url لاراول هم فقط میگه رشته درست پارس میشه؛ هیچ حرفی دربارهٔ اینکه درخواست کجا میره نمیزنه، و سرور تو شبکه جای خیلی متفاوتی از کاربر وایستاده.
خطر اصلی سرویسهای داخلیه. آدرس link-local متادیتای اینستنس روی ماشینهای EC2 که هنوز IMDSv1 دارن اصلاً احراز هویت نداره و اسم رول و کلیدهای موقتش رو برمیگردونه؛ نشت دادهٔ Capital One تو ۲۰۱۹ دقیقاً همین زنجیره بود. متادیتا فقط معروفترین هدفه — پنل ادمین بدون احراز هویت، Elasticsearch داخلی و API کوبرنتیز هم از سمت اپسرور بیدفاعن.
بعد نویسنده هر فیکس بدیهی رو یکییکی میشکنه. بلاک کردن رشتهٔ localhost بیفایدهست، چون همون لوپبک رو میشه اکتال، عدد ۳۲ بیتی، شکل کوتاه inet_aton یا IPv6 هم نوشت. چک کردن رنجهای خصوصی بهتره، ولی مهاجم بهجای IP یه دامنهٔ عمومی میده که رکورد A ش به لوپبک اشاره میکنه. پس چک باید بعد از resolve انجام شه — و اینجا شکاف واقعی باز میشه.
اگه اسم رو یه بار resolve کنی و بعد همون اسم رو به Guzzle بدی، دو تا lookup جدا اتفاق افتاده و هیچی تضمین نمیکنه جوابشون یکی باشه. همین DNS rebinding تو ۲۰۲۳ روی LarkSuite جواب داد و کلیدهای AWS رو بیرون کشید. ریدایرکت ۳۰۲ هم همین شکاف رو داره، چون فقط URL اول چک شده. پژوهش SSRF vs. Developers تو USENIX Security '24 روی ۲۷ هزار پروژهٔ PHP، ۲۳۷ نقطه با ورودی مهاجم پیدا کرد و فقط دوتاشون امن بودن.
نویسنده به همین خاطر همهشو تو پکیج securized/laravel-ssrf جمع کرده: نرمالسازی انکودینگها، چک بعد از resolve، بررسی هر hop ریدایرکت، و گزینهٔ pin_dns که اسم رو یه بار resolve میکنه و مستقیم به همون IP وصل میشه. Http::ssrf() یه PendingRequest معمولیه، پس بقیهٔ زنجیره سر جاشه.
نکات کلیدی:
- قانون url فقط شکل رشته رو چک میکنه، نه مقصد درخواست
- بلاک کردن اسم لوپبک با انکودینگهای جایگزین دور میخوره
- resolve کردن اسم و بعد دادن همون اسم به کلاینت، در rebinding رو باز میذاره
- ریدایرکتها باید hop به hop چک شن
- pin_dns یه بار resolve میکنه و مستقیم به همون IP وصل میشه




