← بازگشت به وبلاگ

نشت رمز عبور پروکسی از طریق کلاینت HTTP: CVE در curl، libsoup و requests

در سال ۲۰۲۶ در curl، libcurl و libsoup آسیب‌پذیری‌هایی پیدا شد که به دلیل آن‌ها هدر Proxy-Authorization به پروکسی نادرست یا به طور مستقیم به سایت هدف ارسال می‌شود. بررسی می‌کنیم که در چه شرایطی این اتفاق می‌افتد، کدام نسخه‌ها ایمن هستند، چگونه می‌توان پارسر خود را با تست زنده بررسی کرد و چگونه می‌توان خسارت را محدود کرد اگر رمز عبور در نهایت نشت کند.

📅۲۵ مهر ۱۴۰۵
نشت رمز عبور پروکسی از طریق کلاینت HTTP: CVE در curl، libsoup و requests

رمز عبور پروکسی معمولاً از مردم محافظت می‌شود: در اسکرین‌شات‌ها نمایش داده نمی‌شود، در git ثبت نمی‌شود و در متغیرهای محیطی نگهداری می‌شود. اما در سال ۲۰۲۶ مشخص شد که خود کلاینت HTTP می‌تواند آن را افشا کند. در ماه‌های آوریل تا ژوئیه چندین آسیب‌پذیری در curl، libcurl و libsoup منتشر شد که در آن‌ها هدر Proxy-Authorization به پروکسی نادرست ارسال می‌شود و گاهی به طور مستقیم به سایت هدف می‌رود. در زیر بررسی می‌شود که این موضوع در چه شرایطی اتفاق می‌افتد و چگونه می‌توان استک خود را مرحله به مرحله بررسی کرد.

چه اتفاقی افتاد: چهار نشت در چهار ماه

همه این باگ‌ها به یک شکل عمل می‌کنند: کلاینت نام کاربری و رمز عبور یک پروکسی را به خاطر می‌سپارد و به اشتباه آن‌ها را به جلو ارسال می‌کند.

  • CVE-2026-6253 (curl و libcurl 7.14.1–8.19.0). اگر برای http:// و https:// پروکسی‌های متفاوتی تنظیم شده باشد، پروکسی اول رمز عبور را درخواست کند و دومی نکند، در هنگام تغییر پروتکل، curl اطلاعات کاربری پروکسی اول را به پروکسی دوم ارسال می‌کند. این اطلاعات به صورت base64 ارسال می‌شود، یعنی در واقع به صورت متن باز. این مشکل در curl 8.20.0 که در ۲۹ آوریل ۲۰۲۶ منتشر شد، برطرف شد. curl کنسولی نیز آسیب‌پذیر است، نه فقط کتابخانه.
  • CVE-2026-8927 (libcurl 7.12.0–8.20.0). برنامه از یک handle برای چندین درخواست استفاده می‌کند، پروکسی‌ها از متغیرهای محیطی گرفته می‌شوند و احراز هویت به صورت Digest انجام می‌شود. در این صورت هدر Proxy-Authorization برای پروکسی A به پروکسی B ارسال می‌شود و آن می‌تواند آن را تکرار کند تا خود را به جای شما معرفی کند. این مشکل در curl 8.21.0 از ۲۴ ژوئن ۲۰۲۶ برطرف شد. curl کنسولی تحت تأثیر قرار نگرفته است. تقریباً همین باگ در CVE-2026-7168 توصیف شده است، تنها تفاوت در نحوه انتخاب پروکسی است.
  • CVE-2026-12547 (libsoup, SoupAuthManager). libsoup اطلاعات کاربری پروکسی را ذخیره می‌کند بدون اینکه آن‌ها را به آدرس host:port مرتبط کند. وقتی تنظیمات پروکسی تغییر می‌کند (پارامترهای سیستمی، WPAD)، هدر قدیمی به پروکسی جدید ارسال می‌شود. این مشکل در ۲۱ ژوئیه ۲۰۲۶ منتشر شد و ارزیابی آن پایین است.
  • CVE-2026-66339 (libsoup, تونل‌های CONNECT). پس از ایجاد تونل CONNECT از طریق پروکسی HTTP، libsoup هدر Proxy-Authorization را به درخواست‌های HTTPS بعدی درون تونل متصل می‌کند. این هدر توسط سرور هدف مشاهده می‌شود. CVSS 6.5، منتشر شده در ۲۴ ژوئیه ۲۰۲۶.

این تاریخچه جدید نیست. در کتابخانه Python requests از نسخه ۲.۳.۰ تا ۲.۳۱.۰ (CVE-2023-32681) هدر Proxy-Authorization در هنگام تغییر به HTTPS به سرور هدف ارسال می‌شد، اگر نام کاربری و رمز عبور به طور مستقیم در URL پروکسی وارد شده بودند. در urllib3 تا ۱.۲۶.۱۹ و ۲.۲.۲ (CVE-2024-37891) هدر به صورت دستی تنظیم شده، نه از طریق پشتیبانی داخلی پروکسی، در هنگام تغییر به دامنه دیگر حذف نمی‌شد.

چرا این موضوع برای کار با پروکسی مهم است

در پروکسی‌های پولی، رمز عبور معادل پول است. هر کسی که آن را به دست آورد، ترافیک شما را مصرف می‌کند تا زمانی که شما دسترسی را تغییر دهید. هنگام پرداخت برای گیگابایت‌ها، این یک هزینه مستقیم است و در صورت دسترسی عمومی برای کل تیم، اقدامات دیگران با IP شما نیز شامل می‌شود.

سناریوهای آسیب‌پذیر به این شکل هستند:

  • پارس‌ها و مانیتورها که به طور خودکار از طریق تغییرات می‌روند. سایت هدف یا تغییر مسیر می‌تواند درخواست را به دامنه‌ای که هدرها را جمع‌آوری می‌کند، هدایت کند.
  • اسکریپت‌ها با چندین پروکسی: پروکسی‌های مختلف برای پروتکل‌های مختلف، تغییر پروکسی بین درخواست‌ها در یک اتصال، ترکیب «پروکسی با رمز عبور» و «پروکسی بدون رمز عبور».
  • فرآیندهای بلندمدت در سرورهای لینوکس که در آن libcurl و libsoup با بسته‌های سیستمی می‌آیند و با توزیع به‌روزرسانی می‌شوند، نه با کد شما.
  • شبکه‌های شرکتی با WPAD و فایل‌های PAC: پروکسی بدون دخالت برنامه تغییر می‌کند و این مورد دقیقاً در CVE-2026-12547 توصیف شده است.

چگونه استک خود را بررسی کنیم: مرحله به مرحله

  1. نسخه واقعی libcurl را پیدا کنید، نه فقط curl کنسولی. دستور curl -V هر دو را نشان می‌دهد، اما برنامه ممکن است با نسخه خود از کتابخانه ساخته شده باشد. برای Python با pycurl، دستور python -c "import pycurl; print(pycurl.version)" را اجرا کنید، برای PHP curl_version() را فراخوانی کنید. مرز ایمنی: ۸.۲۱.۰ و جدیدتر یا شاخه‌های اصلاح شده ۸.۲۰.۱+، ۸.۱۶.۱+ و ۸.۱۴.۲+.
  2. وابستگی‌های Python را بررسی کنید. دستور pip show requests urllib3 را اجرا کنید. به requests نیاز دارید که کمتر از ۲.۳۱.۰ نباشد و urllib3 کمتر از ۱.۲۶.۱۹ (شاخه ۱.x) یا ۲.۲.۲ (شاخه ۲.x) نباشد. اگر وابستگی به صورت غیرمستقیم می‌آید، در همان محیطی که پارسر کار می‌کند، pip list را بررسی کنید.
  3. libsoup را در لینوکس بررسی کنید. این موضوع شامل برنامه‌های GNOME، WebKitGTK و هر چیزی است که بر روی این استک ساخته شده است. بسته را از طریق مدیر توزیع به‌روزرسانی کنید و با بولتن امنیتی توزیع خود مطابقت دهید: در کارت‌های این CVE در Red Hat، RHEL 6–10 به عنوان آسیب‌پذیر ذکر شده‌اند.
  4. در کد، نصب دستی هدر را پیدا کنید. جستجو در Proxy-Authorization در کل مخزن. اگر هدر به صورت دستی تنظیم می‌شود و نه از طریق مکانیزم استاندارد پروکسی کلاینت (proxies= در requests، ProxyManager در urllib3، CURLOPT_PROXYUSERPWD در libcurl)، این یک کاندید برای نشت در هنگام تغییر مسیر است.
  5. استفاده مجدد از اتصالات را در هنگام تغییر پروکسی پیدا کنید. یک handle libcurl، یک جلسه requests یا یک عامل HTTP که به نوبت درخواست‌ها را با پروکسی‌های مختلف ارسال می‌کند. ساده‌ترین راه حل: یک جلسه جداگانه برای هر پروکسی.
  6. خودکار کردن تغییر مسیرها را در جاهایی که لازم نیست، غیرفعال کنید. در requests این allow_redirects=False است، در urllib3 redirect=False، در curl -L و CURLOPT_FOLLOWLOCATION را قرار ندهید. در این صورت ۳xx به صورت دستی پردازش می‌شوند و شما خودتان تصمیم می‌گیرید که به کجا بروید. این دور زدن را نویسندگان requests و urllib3 ارائه می‌دهند.
  7. یک تست زنده برای تله انجام دهید. یک سرور HTTP ساده را راه‌اندازی کنید که تمام هدرهای دریافتی را چاپ می‌کند و بر روی آن یک تغییر مسیر به سرور دوم مشابه انجام دهید. سناریوی واقعی خود را با پروکسی از طریق پارسر خود اجرا کنید، از جمله تغییر پروتکل از http به https. اگر هر یک از سرورها هدر Proxy-Authorization را مشاهده کرد، نشت در کد شما تأیید شده است، نه در تئوری.

دام‌های پنهان

  • تصاویر Docker زندگی خود را دارند. curl را در هاست به‌روزرسانی کردید، اما پارسر در کانتینری با تصویر پایه قدیمی کار می‌کند. باید درون کانتینر بررسی کنید: docker exec <کانتینر> curl -V.
  • curl کنسولی و libcurl به طور متفاوتی به‌روزرسانی می‌شوند. CVE-2026-8927 بر curl کنسولی تأثیری ندارد، اما CVE-2026-6253 بر آن تأثیر می‌گذارد. curl -V جدید در ترمینال هیچ چیزی درباره کتابخانه‌ای که PHP یا Python شما با آن ساخته شده است نمی‌گوید.
  • Digest نجات نمی‌دهد. بله، در Digest رمز عبور به صورت متن باز ارسال نمی‌شود. اما در CVE-2026-8927، حمله‌کننده به رمز عبور نیازی ندارد: هدر ضبط شده را تکرار می‌کند تا nonce معتبر باشد.
  • رمز عبور در URL راحت است، اما خطرناک است. نشت در requests دقیقاً زمانی رخ می‌دهد که اطلاعات کاربری در آدرس پروکسی به صورت user:pass@host:port وارد شده باشد. این دلیل نمی‌شود که از این فرمت صرف‌نظر کنید، اما دلیلی برای به‌روز نگه‌داشتن کتابخانه‌هاست.
  • تغییر مسیر ممکن است از هدف نیاید. صفحات کپچا، بنرهای توافق، کوتاه‌کننده‌های لینک و CDN نیز به ۳xx پاسخ می‌دهند. هرچه در خزنده «پیروی از لینک‌ها» بیشتر باشد، سطح حمله وسیع‌تر است.

چگونه آسیب را محدود کنیم اگر رمز عبور در نهایت افشا شود

به طور کامل نمی‌توان نشت را حذف کرد: فردا CVE بعدی منتشر می‌شود. بنابراین مهم است که یک نشت چقدر هزینه دارد.

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

چه نوع پروکسی را انتخاب کنیم و چه ارتباطی دارد

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

نتیجه‌گیری

رمز عبور پروکسی می‌تواند بدون هک، بدون ویروس و بدون خطای انسانی نشت کند: فقط کافی است libcurl قدیمی، تغییر مسیر به دامنه خارجی و استفاده مجدد از اتصال وجود داشته باشد. چک‌لیست کوتاه است: curl و libcurl از ۸.۲۱.۰، requests از ۲.۳۱.۰، urllib3 از ۱.۲۶.۱۹ یا ۲.۲.۲، libsoup جدید، جلسه جداگانه برای هر پروکسی، تغییر مسیرها تحت کنترل و یک تست زنده برای تله. به علاوه، دسترسی جداگانه برای هر پروژه، تا یک نشت فقط هزینه یک اسکریپت را داشته باشد، نه تمام موجودی.