جلوگیری از SSRF تو لاراول با یه پکیج آماده
خلاصهٔ کاملتر
فچ کردن یه URL که کاربر داده کار عجیبی نیست؛ وبهوک، پیشنمایش لینک و ایمپورت آواتار همه همینن. مشکل اینجاست که سرور اون درخواست رو از یه موقعیت شبکهای میفرسته که خود کاربر بهش دسترسی نداره. تو مستندات این پکیج اومده که یه آدرس دستکاریشده از همین راه میتونه به Redis روی لوکالهاست، پنل ادمین داخلی یا نقطهٔ متادیتای ابری (آدرس link-local معروف 169.254.169.254) برسه و روی EC2 وصلهنشده حتی کلیدهای IAM سرور رو برگردونه.
به گفتهٔ نویسنده بستن این در سختتر از چیزیه که به نظر میرسه: همون 127.0.0.1 رو میشه به شکل اکتال، عدد صحیح یا معادل IPv6 هم نوشت، و دامنهای که موقع بررسی به یه IP عمومی resolve میشه، یه لحظه بعد موقع اتصال Guzzle میتونه به آدرس داخلی اشاره کنه. laravel-ssrf هر URL رو قبل از اینکه درخواست از اپلیکیشن بیرون بره اعتبارسنجی میکنه.
راهاندازیش کوتاهه؛ بعد از نصب با composer کافیه هر فراخوانی HTTP کلاینت لاراول رو با ماکرو ssrf() بپیچی:
use Illuminate\Support\Facades\Http;
// Wrap any Http:: call with ->ssrf() to enable protection
Http::ssrf()->get($userSuppliedUrl);
Http::ssrf()->post($webhookUrl, $payload);از این به بعد درخواست به IPهای خصوصی، لوکالهاست، آدرسهای link-local و اسکیمهای غیر HTTP(S) بلاک میشه و همون RequestException آشنای Guzzle پرتاب میشه، پس مدیریت خطای فعلی پروژه دستنخورده میمونه.
کنار این ماکرو، میدلور خام برای Guzzle، قاعدهٔ اعتبارسنجی SsrfSafeUrl برای فرمریکوئستها و یه Facade به اسم Ssrf با متدهای validate()، isSafe() و safeUrl() هم هست. با SSRF_AUTO_PROTECT تو فایل env میشه همهٔ درخواستهای Http:: رو یکجا محافظت کرد. لیست سفید و سیاه هم جدا جدا برای IP (با CIDR)، پورت، دامنه و اسکیم تعریف میشن و لیست سیاه همیشه اولویت داره.
مستندات پکیج محدودیتهاش رو هم صادقانه میگه: ریدایرکتها پوشش داده میشن چون میدلور تو هر hop دوباره اجرا میشه، ولی اگه خودت آدرسی رو از دل صفحهٔ فچشده دربیاری و دوباره درخواست بدی، اعتبارسنجی اون با خودته. بدون فعال کردن pin_dns هم پنجرهٔ TOCTOU باز میمونه و سرویس داخلیای که روی IP عمومی نشسته اصلاً شناخته نمیشه. مدل تهدید و بخش زیادی از ساختار تستها هم از مقالهٔ USENIX Security '24 دربارهٔ دفاعهای SSRF در PHP گرفته شده.
نکات کلیدی:
- Http::ssrf() هر درخواست خروجی لاراول رو قبل از ارسال اعتبارسنجی میکنه
- IPهای خصوصی، لوکالهاست، link-local و اسکیمهای غیر HTTP(S) پیشفرض بلاک میشن
- pin_dns جلوی DNS rebinding رو میگیره و ریدایرکتها هم تو هر hop چک میشن
- میدلور Guzzle، قاعدهٔ اعتبارسنجی و Facade برای حالتهای مختلف در دسترسه
- درخواستهای مرتبهٔ دوم و سرویس داخلی روی IP عمومی پوشش داده نمیشن




