maksec.
متوسطامنیت وبعمومی

Server Side Open Redirect در فرایند پرداخت

وقتی یک لینک معتبر پرداخت، کاربر را به هر مقصدی هدایت می‌کند

وبOpen Redirect~2 min
open redirect

🔀 وقتی مقصد Redirect حتی در خود لینک هم دیده نمی‌شد

مقدمه

بعضی از آسیب‌پذیری‌ها با دیدن یک پارامتر مشکوک تقریباً بلافاصله خودشان را نشان می‌دهند.

اما گاهی داستان متفاوت است.

ممکن است پارامتری که کنترل مقصد Redirect را در اختیار دارد، در جایی از فرآیند وجود داشته باشد، اما وقتی لینک نهایی را مشاهده می‌کنید، هیچ اثری از آن پارامتر وجود نداشته باشد.

این دقیقاً چیزی بود که در جریان بررسی یک فرآیند پرداخت با آن مواجه شدم.


🔎 شروع ماجرا

در جریان بررسی فرآیند ایجاد تراکنش، با پارامتری مواجه شدم که ظاهراً برای مشخص کردن مقصد بازگشت کاربر استفاده می‌شد:

text
redirectUrl

در نگاه اول، رفتار کاملاً معمولی بود.

مقدار این پارامتر می‌توانست یک مسیر داخلی از همان سرویس باشد.

اما یک سؤال ساده مطرح شد:

آیا این مقدار واقعاً در سمت سرور قابل اعتماد است؟

برای بررسی، مقدار مقصد را به یک دامنه خارجی تحت کنترل تست تغییر دادم.


🧪 دنبال کردن جریان

بعد از ایجاد تراکنش، فرآیند پرداخت را تا مرحله بازگشت از درگاه دنبال کردم.

اینجا اولین نکته جالب مشخص شد.

پس از بازگشت، کاربر به یک URL معتبر از سرویس هدایت می‌شد؛ چیزی شبیه:

text
https://trusted-service.example/complete/payment/callback?id=xxx

در این URL هیچ چیزی شبیه:

text
?redirectUrl=...

وجود نداشت.

حتی اگر کسی لینک را Copy کند، آن را بررسی کند یا با ابزارهایی مثل Burp Suite صرفاً URL نهایی را نگاه کند، هیچ نشانه مستقیمی از مقصد خارجی در خود لینک Callback دیده نمی‌شود.


💥 بخش جالب آسیب‌پذیری

در همین نقطه متوجه شدم رفتار Redirect در واقع در سمت سرور اتفاق می‌افتد.

جریان به این شکل بود:

text
Client
  │
  │ redirectUrl = external destination
  ▼
Server
  │
  │ stores/processes destination
  ▼
Payment Gateway
  │
  │ callback
  ▼
Server
  │
  │ Server-Side Redirect
  ▼
External Domain

یعنی مقصد نهایی در URL قابل مشاهده قربانی قرار نداشت.

هیچ redirectUrlای در لینک Exploit نهایی وجود نداشت.

هیچ دامنه خارجی‌ای در URL قابل مشاهده نبود.

و حتی یک کاربر فنی که لینک را بررسی می‌کرد، صرفاً با نگاه کردن به URL نمی‌توانست متوجه شود که این لینک در نهایت به یک دامنه خارجی Redirect خواهد شد.

این موضوع، یکی از جالب‌ترین بخش‌های این یافته بود.


🎭 لینک کاملاً معتبر به نظر می‌رسید

فرض کنید مهاجم لینک زیر را برای قربانی ارسال کند:

text
https://trusted-service.example/complete/payment/callback?id=xxx

از دید قربانی:

  • دامنه معتبر است.
  • مسیر ظاهراً مربوط به فرآیند پرداخت است.
  • پارامتر مشکوکی در URL وجود ندارد.
  • مقصد خارجی در URL قابل مشاهده نیست.

اما پس از پردازش درخواست توسط سرور، کاربر به مقصدی خارجی هدایت می‌شود.

در واقع، لینک Exploit خودش هیچ سرنخ واضحی درباره Redirect خارجی ندارد.

این مسئله می‌تواند سوءاستفاده در سناریوهای مهندسی اجتماعی را ساده‌تر کند، زیرا قربانی قبل از کلیک با یک URL کاملاً معتبر مواجه است.


🧠 چرا Server-Side Redirect مهم است؟

در برخی Open Redirectها، مقصد مستقیماً داخل URL قرار دارد:

text
https://trusted.example/redirect?url=https://attacker.example

در چنین شرایطی، حتی یک کاربر عادی هم ممکن است متوجه شود که مقصد لینک یک سایت خارجی است.

اما در این سناریو:

text
https://trusted-service.example/complete/payment/callback?id=xxx

لینک نهایی هیچ نشانه‌ای از مقصد خارجی ندارد.

سرور پس از دریافت درخواست، منطق Redirect را اجرا می‌کند و سپس پاسخ Redirect را به Client برمی‌گرداند.

بنابراین می‌توان این رفتار را به‌صورت دقیق‌تر یک:

Server-Side Open Redirect

توصیف کرد.


⚠️ Impact

این رفتار می‌تواند در سناریوهای زیر مورد سوءاستفاده قرار بگیرد:

  • Phishing: استفاده از اعتبار یک دامنه قابل اعتماد برای هدایت کاربر به سایت مهاجم
  • Social Engineering: ساخت لینک‌هایی که در نگاه اول کاملاً معتبر به نظر می‌رسند
  • Brand Abuse: سوءاستفاده از اعتبار دامنه اصلی
  • Attack Chaining: استفاده از Open Redirect به‌عنوان بخشی از یک زنجیره حمله بزرگ‌تر

مهم‌ترین نکته این است که لینک نهایی به‌تنهایی اطلاعاتی درباره مقصد واقعی Redirect در اختیار قربانی قرار نمی‌دهد.


🛡️ راهکار پیشنهادی

برای جلوگیری از این نوع رفتار:

1. Allowlist

فقط مقصدهایی که از قبل مورد اعتماد هستند اجازه Redirect داشته باشند.

2. محدود کردن مقصد به مسیرهای داخلی

بهتر است به‌جای دریافت URL کامل، تنها مسیر داخلی دریافت شود:

text
/dashboard
/account
/payment/history

3. اعتبارسنجی Server-Side

سرور باید قبل از Redirect بررسی کند که مقصد متعلق به دامنه یا مجموعه مقصدهای مجاز است.

4. عدم اعتماد به ورودی Client

هر مقداری که از سمت Client برای تعیین مقصد Redirect دریافت می‌شود باید غیرقابل اعتماد در نظر گرفته شود.


📌 جمع‌بندی

این آسیب‌پذیری از یک پارامتر ساده شروع شد؛ اما چیزی که آن را جالب‌تر می‌کرد، نحوه نهایی شدن Redirect بود.

مقصد خارجی در لینک قابل مشاهده قرار نداشت.

در نتیجه، لینک نهایی می‌توانست کاملاً معتبر به نظر برسد:

text
https://trusted-service.example/complete/payment/callback?id=xxx

اما پشت صحنه، سرور تصمیم می‌گرفت کاربر را به مقصد دیگری هدایت کند.

به همین دلیل، حتی بررسی خود URL نیز لزوماً نمی‌توانست ماهیت Redirect را آشکار کند.

گاهی یک آسیب‌پذیری نه به خاطر پیچیدگی تکنیکی، بلکه به خاطر این‌که چقدر خوب در جریان عادی برنامه پنهان شده است، جالب می‌شود.

و این یکی از همان موارد بود.

این رایت‌آپ را خواندید؟ اگر روی پروژه یا پژوهش مشابهی کار می‌کنید، برای همکاری در تماس باشید.