برای سایتی که صاحبش مطمئن بود چون همه افزونه‌ها به‌روزند پس هیچ حفره‌ای ندارد، در پوشه wp-content/uploads یک فایل PHP پیدا کردم که با یک پارامتر ساده در URL اجرا می‌شد و امکان خواندن فایل‌های سرور را می‌داد. آن روز برای من روشن شد که یافتن آسیب‌پذیری (vulnerability) فقط زدن دکمه اسکن نیست؛ یک نگاه روش‌مند به تمام سطوح سایت است. این نوشته، همان روشی است که در پروژه‌های واقعی برای پیدا کردن آسیب‌پذیری به کار می‌برم.

آسیب‌پذیری چیست و چرا پیدا کردنش یک مهارت است؟

آسیب‌پذیری یا vulnerability، یک ضعف در کد، پیکربندی (configuration) یا منطق برنامه است که می‌تواند توسط یک مهاجم به نفع خودش به کار گرفته شود. اما چرا پیدا کردن آن یک مهارت جدا محسوب می‌شود و نه یک وظیفه روتین؟ چون آسیب‌پذیری همیشه آنجایی نیست که ابزار نشان می‌دهد. بسیاری از حفره‌های واقعی که در پروژه‌ها دیده‌ام، از جنس منطق کسب‌وکار (business logic) بوده‌اند، نه از جنس کد قابل‌اسکن. مثلاً یک endpoint که بدون بررسی مالکیت، اطلاعات کاربر دیگری را برمی‌گرداند — چیزی که هیچ اسکنری به تنهایی نمی‌تواند بفهمد.

اینجاست که تفاوت میان آسیب‌پذیری، تهدید و ریسک معنادار می‌شود. آسیب‌پذیری یک ضعف است؛ تهدید (threat) کسی است که از آن استفاده می‌کند؛ و ریسک (risk) ترکیب احتمال وقوع و اثر آن است. اگر این تفکیک را در ذهن نداشته باشید، فهرست بلندی از آسیب‌پذیری‌ها تولید می‌کنید که هیچ‌کدام به کسب‌وکار شما مربوط نیستند و در نهایت همه را نادیده می‌گیرید. برای درک پایه‌ای مفهوم، پیشنهاد می‌کنم ابتدا آسیب‌پذیری وب چیست و چگونه شناسایی می‌شود را بخوانید و بعد به سراغ این مقاله برگردید.

پیدا کردن آسیب‌پذیری، مثل معاینه خانه است: ابزار به شما می‌گوید دیوار ترک دارد؛ اما فقط چشمِ آموزش‌دیده می‌فهمد آن ترک، نشانه ریزش پی است یا فقط رنگ‌آمیزی سطحی.

نقشه‌برداری از سطح حمله

قبل از هر اسکن یا تحلیل کد، یک نقشه از سطح حمله (attack surface) سایت خودتان بکشید. سطح حمله، مجموعه‌ای از نقاطی است که یک مهاجم می‌تواند از بیرون به آن‌ها دسترسی پیدا کند. در یک سایت وردپرسی معمولی، این نقاط شامل موارد زیر است:

  • پیشخوان ورود (wp-login.php) و مسیرهای ورود سفارشی
  • REST API و endpointهای پیش‌فرض مثل /wp-json/wp/v2/users
  • فرم‌های عمومی: تماس، عضویت، جستجو، دیدگاه
  • مسیرهای آپلود و کتابخانه رسانه
  • افزونه‌ها و قالب‌های فعال و غیرفعال
  • سرویس‌های جانبی: ایمیل، پرداخت، CDN، ابزار تحلیل
  • فایل‌های پیکربندی و پشتیبان جا‌مانده

هر نقطه از این نقشه، یک فرض حمله (attack hypothesis) تازه می‌سازد. مثلاً اگر فرم عضویت دارید، سوال بعدی این است: آیا ورودی فیلد نام کاربری قبل از ذخیره در دیتابیس پاک‌سازی (sanitize) می‌شود؟ آیا فرم در برابر CSRF محافظت دارد؟ آیا نرخ درخواست محدود است؟ این پرسش‌ها همان چیزی است که نقشه سطح حمله را از یک فهرست ساده جدا می‌کند. برای آشنایی با انواع شایع این حفره‌ها، انواع آسیب‌پذیری‌های رایج وب را مرور کنید.

سه خانواده آسیب‌پذیری: کد، پیکربندی، وابستگی

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

خانوادهنشانهنمونه رایج
آسیب‌پذیری کدمنطق برنامه یا اعتبارسنجی ناقصIDOR، XSS ذخیره‌شده، SQL Injection
آسیب‌پذیری پیکربندیفایل یا سرویس با دسترسی اشتباهنمایش خطا، دایرکتوری باز، رمز پیش‌فرض
آسیب‌پذیری وابستگینسخه قدیمی کتابخانه یا افزونهCVE در افزونه، کتابخانه JavaScript قدیمی

نکته مهم این است که هر سه خانواده را نمی‌توان با یک ابزار پیدا کرد. آسیب‌پذیری کد، نیاز به خواندن دارد؛ آسیب‌پذیری پیکربندی، نیاز به بازرسی سرور دارد؛ و آسیب‌پذیری وابستگی، نیاز به تطبیق با فهرست CVE (Common Vulnerabilities and Exposures) دارد. برای درک ساختار این فهرست، CVE چیست و چه نقشی در امنیت دارد را ببینید.

روش‌های دستی: تحلیل منطق و کد

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

  1. آیا هر درخواست، مالکیت را چک می‌کند؟ اگر کاربری با شناسه ۱۰ بتواند با تغییر شناسه در URL، اطلاعات کاربر ۱۱ را ببیند، یک IDOR (Insecure Direct Object Reference) دارید. جزئیات این نوع حفره را در آسیب‌پذیری IDOR چیست جدا نوشته‌ام.
  2. آیا ورودی‌ها قبل از نمایش، خروجی‌گیری امن (escaping) می‌شوند؟ اگر داده‌ای از دیتابیس بدون esc_html() یا معادل آن چاپ شود، احتمال XSS ذخیره‌شده بالا می‌رود.
  3. آیا فایل‌ها با مسیر ورودی کاربر خوانده می‌شوند؟ الگوهای include و file_get_contents که مسیرشان از پارامتر دریافت می‌کنند، کانون LFI و RFI هستند. مقایسه این دو را در تفاوت RFI و LFI توضیح داده‌ام.
  4. آیا پردازش ورودی‌ها قبل از ذخیره اعتبارسنجی می‌شود؟ نبود sanitize_* یا absint() روی گزینه‌های ذخیره‌شده، بستر آسیب‌پذیری‌های ثانویه است.

تحلیل دستی کد، به‌خصوص در پروژه‌هایی که کد سفارشی دارند، گاهی از هر اسکنری دقیق‌تر عمل می‌کند؛ چون اسکنر منطق کسب‌وکار شما را نمی‌فهمد.

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

اسکنرها چه چیزی را پیدا می‌کنند و چه چیزی را نه؟

اسکنرهای آسیب‌پذیری وب (web vulnerability scanners) در دو دسته کلی قرار می‌گیرند: اسکنرهای سطح وب که سایت را از بیرون می‌کاوند، و اسکنرهای سطح کد که فایل‌ها را از داخل بررسی می‌کنند. هر کدام نقاط قوت و کور مشخصی دارند:

نوعپیدا می‌کنداز دست می‌دهد
اسکنر وب (وب‌محور)خطاهای پیکربندی، نسخه‌های آسیب‌پذیر، فرم‌های بدون محافظت، هدرهای امنیتی ناقصمنطق کسب‌وکار، آسیب‌پذیری احراز‌شده، مسیرهای پنهان
اسکنر کد (سطح فایل)الگوهای ناامن در PHP، افزونه‌های مشکوک، فایل‌های جا‌ماندهرفتار زمان اجرا، تعامل با دیتابیس، حملات مبتنی بر منطق

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

شکار سریع در قالب و افزونه‌های وردپرس

در سایت‌های وردپرسی، بخش بزرگی از آسیب‌پذیری‌ها از قالب و افزونه می‌آید. چند مورد که تقریباً همیشه در بررسی‌ها به آن‌ها می‌رسم:

  • فایل‌های جا‌مانده در پوشه آپلود: فایل‌های .php یا .bak در wp-content/uploads تقریباً همیشه یک نشانه است.
  • افزونه‌های غیرفعال اما نصب‌شده: آسیب‌پذیری یک افزونه غیرفعال هم می‌تواند اجرا شود اگر فایل‌هایش در دسترس باشند. فهرست ریسک‌ها را در آسیب‌پذیری افزونه‌های وردپرس آورده‌ام.
  • کد سفارشی در functions.php: توابع بدون پاک‌سازی ورودی و evalهای پنهان.
  • نسخه‌های قدیمی: مقایسه نسخه فعلی افزونه با آخرین نسخه پایدار در مخزن رسمی.
  • منبع دانلود مشکوک: افزونه‌ها و قالب‌های نال، کانون کلاسیک درج در پشتی هستند؛ پیش از هر چیز چک‌لیست دانلود افزونه مطمئن را اجرا کنید.

برای بررسی ساختارمند قالب و افزونه، روشی که در بررسی امنیت قالب و افزونه وردپرس توضیح داده‌ام را گام‌به‌گام اجرا کنید. علاوه بر این، یک افزونه امنیتی درست‌تنظیم‌شده می‌تواند برخی از این حفره‌ها را زودتر لو بدهد؛ فهرست بهترین افزونه‌های امنیتی وردپرس را در همین راستا ببینید.

اولویت‌بندی با CVSS و زمینه کسب‌وکار

پیدا کردن آسیب‌پذیری، نیمی از کار است؛ اولویت‌بندی، نیم دیگر. فرض کنید سه آسیب‌پذیری پیدا کرده‌اید: یک XSS ذخیره‌شده در بخش دیدگاه، یک IDOR در پنل مدیریت، و یک نسخه قدیمی از یک کتابخانه JavaScript که به‌ندرت در قالب استفاده می‌شود. کدام اول؟

امتیاز CVSS (Common Vulnerability Scoring System) به شما یک عدد می‌دهد، اما عدد به‌تنهایی تصمیم نیست. باید وزن کسب‌وکار را هم اضافه کنید: IDOR در پنل مدیریت، اگر پنل شما به اینترنت باز است و ادمین‌های متعددی دارد، بسیار خطرناک‌تر از یک XSS در دیدگاه عمومی است. روش مرحله‌به‌مرحله این تصمیم‌گیری را در چگونه آسیب‌پذیری‌ها را رتبه‌بندی و رفع کنیم آورده‌ام.

پیدا کردن ده آسیب‌پذیری و رفع نکردن هیچ‌کدام، بدتر از پیدا کردن یک آسیب‌پذیری و رفع آن است. مهارت واقعی، در انتخاب است نه در فهرست کردن.

اشتباهات رایج در فرآیند یافتن

چند الگوی تکراری که در پروژه‌های مختلف دیده‌ام و هر بار هزینه‌ای داشته‌اند:

  • اسکن روی سایت زنده بدون هماهنگی: بعضی اسکنرها با حجم بالای درخواست، سایت را می‌خوابانند. همیشه روی استجینگ یا در بازه کم‌ترافیک.
  • اعتماد مطلق به خروجی اسکنر: نبود هشدار، به‌معنی نبود آسیب‌پذیری نیست؛ فقط یعنی اسکنر آن را پیدا نکرده.
  • نادیده گرفتن نقش کاربری: یک آسیب‌پذیری که برای ادمین بی‌خطر است، برای نقش نویسنده می‌تواند جدی باشد. تست با نقش‌های مختلف را فراموش نکنید.
  • فراموش کردن ساب‌دامین‌ها: نقطه ورود همیشه دامنه اصلی نیست؛ یک ساب‌دامین فراموش‌شده می‌تواند ضعیف‌ترین حلقه باشد.
  • ترس از ثبت نتایج: اگر یافته‌ها را جایی ثبت نکنید، ماه بعد همان آسیب‌پذیری‌ها را دوباره پیدا می‌کنید. یک فهرست ساده با تاریخ و وضعیت رفع، اولین قدم مدیریت است. برای مرور کلی اشتباهات در این زمینه، اشتباهات رایج در مدیریت آسیب‌پذیری‌ها را ببینید.

پاسخ‌های کوتاه برای موتورهای پاسخ‌ده

بخش زیر برای بهینه‌سازی در موتورهای پاسخ‌ده (AEO – Answer Engine Optimization) نوشته شده و پاسخ‌های کوتاه و مستقیم به پرسش‌های پرتکرار را در اختیار این موتورها قرار می‌دهد:

  • آسیب‌پذیری سایت چیست؟ ضعفی در کد، پیکربندی یا منطق برنامه که می‌تواند توسط مهاجم برای دسترسی غیرمجاز، تغییر داده یا تخریب استفاده شود.
  • چگونه آسیب‌پذیری سایت را پیدا کنیم؟ با نقشه‌برداری سطح حمله، تحلیل دستی منطق و کد، استفاده هدفمند از اسکنرها و تطبیق نسخه‌ها با فهرست CVE.
  • بهترین ابزار یافتن آسیب‌پذیری سایت چیست؟ ابزار واحد وجود ندارد؛ ترکیب یک اسکنر وب، یک اسکنر کد و بازبینی دستی توسط فرد آشنا به منطق کسب‌وکار مؤثرترین روش است.
  • آیا اسکنرها کافی هستند؟ نه. اسکنرها نمی‌توانند آسیب‌پذیری‌های منطقی مثل IDOR یا نقص در بررسی نقش کاربری را تشخیص دهند.

حرف آخر

یافتن آسیب‌پذیری سایت یک فعالیت یک‌باره نیست؛ یک فرآیند است که با نقشه‌برداری شروع می‌شود، با تحلیل دستی ادامه پیدا می‌کند، با اسکنرها سرعت می‌گیرد و با اولویت‌بندی معنادار می‌شود. اگر امروز فقط یک کار می‌کنید، همان فهرست ساده سطح حمله را بنویسید و کنار هر آیتم، یک فرض حمله و یک اقدام پیشگیرانه اضافه کنید. همین یک برگه، ماه بعد شما را از صدها گزارش اسکنر بی‌رابطه نجات می‌دهد. اگر در پروژه‌ای حفره‌ای پیدا کرده‌اید که هیچ اسکنری آن را ندیده بود، برای من جالب است بدانم از کدام جنس بود و چطور به آن رسیدید. تجربه‌تان را در دیدگاه‌ها بنویسید؛ خواننده بعدی، با همین جزئیات از یک شکست تکراری نجات پیدا می‌کند. 🔍