SSRF Prevention در وردپرس چطور انجام میشود؟
SSRF Prevention در وردپرس جلوی دسترسی سرور به منابع داخلی از طریق ورودی کاربر را میگیرد. جلوگیری از این آسیبپذیری نیازمند اعتبارسنجی URL و مسدودسازی درخواستهای داخلی است.
SSRF Prevention (پیشگیری از جعل درخواست سمت سرور) در وردپرس یکی از حیاتیترین لایههای امنیتی است که متأسفانه بسیاری از توسعهدهندگان آن را نادیده میگیرند. SSRF (Server-Side Request Forgery - جعل درخواست سمت سرور) نوعی آسیبپذیری است که در آن مهاجم با دستکاری ورودیهایی که سرور برای ارسال درخواست HTTP استفاده میکند، سرور را وادار به ارسال درخواست به مقصد دلخواه میکند. در وردپرس، مسیرهای ورود شامل توابع wp_remote_get()، wp_remote_post()، oEmbed، XML-RPC، و افزونههایی است که URL کاربر را پردازش میکنند. پیامدهای موفقیت این حمله میتواند از دسترسی به سرویسهای داخلی شبکه، خواندن متادیتای ابری، تا نفوذ کامل به زیرساخت متغیر باشد. دفاع اصلی شامل اعتبارسنجی سختگیرانه URL، استفاده از wp_safe_remote_*، مسدودسازی آدرسهای داخلی، و غیرفعالسازی oEmbed در صورت عدم نیاز است. بدون درک دقیق مکانیزم SSRF، پیادهسازی دفاعی مؤثر ممکن نیست.
نخستینباری که با SSRF روبهرو شدیم، در یک پروژه بررسی امنیتی بود که در آن یک افزونه نمایش لینک، آدرس ورودی کاربر را مستقیماً به wp_remote_get() میفرستاد. مهاجم میتوانست با ارسال آدرس http://169.254.169.254/latest/meta-data/، متادیتای سرور ابری را بخواند. از آن زمان، هر جا صحبت از پردازش URL در وردپرس باشد، SSRF را جدی میگیریم. در این نوشتار، از ریشههای فنی تا دفاع عملی را بررسی میکنیم.
SSRF چیست و چرا یک تهدید جدی است؟
SSRF (Server-Side Request Forgery - جعل درخواست سمت سرور) نوعی آسیبپذیری است که در آن مهاجم با کنترل URL ورودی، سرور قربانی را وادار به ارسال درخواست HTTP به مقصد دلخواه میکند. برخلاف XSS که هدفش مرورگر است، SSRF در سطح سرور عمل میکند و میتواند به منابعی دسترسی پیدا کند که از بیرون غیرقابل دسترس هستند. این آسیبپذیری در OWASP Top 10 سال ۲۰۲۱ در دسته A10 با عنوان «Server-Side Request Forgery» قرار گرفت.
تفاوت کلیدی SSRF با حملات تزریقی دیگر در این است که مهاجم «کد» تزریق نمیکند، بلکه «مقصد درخواست» را دستکاری میکند. همین ویژگی، آن را به یک تهدید «مرزی» تبدیل میکند: از لایه برنامه شروع میشود اما به لایه شبکه و زیرساخت میرسد. برای درک جایگاه این آسیبپذیری در دستهبندی کلی، انواع آسیبپذیریهای رایج وب را ببینید.
SSRF یک حمله «از درون» است: سرور قربانی، خودش به مهاجم کمک میکند به منابع داخلی دسترسی پیدا کند. به همین دلیل، فایروالهای سنتی آن را نمیبینند.
مسیرهای ورود SSRF در وردپرس
وردپرس در چندین نقطه از ارسال درخواست HTTP استفاده میکند. هر یک از این نقاط، یک سطح حمله بالقوه است:
- توابع
wp_remote_get()وwp_remote_post(): ابزار اصلی وردپرس برای ارتباط با سرویسهای خارجی. - oEmbed: برای جاسازی محتوای خارجی، URL کاربر را پردازش میکند.
- XML-RPC: درگاه سنتی وردپرس برای ارتباط با اپلیکیشنهای خارجی.
- افزونههای همگامسازی: بسیاری از افزونهها از APIهای خارجی داده میگیرند.
- افزونههای اسکرپینگ: هر افزونهای که URL کاربر را برای دریافت محتوا پردازش کند.
- REST API: برخی افزونهها endpointهایی برای دریافت URL دارند.
نکته مهم این است که وردپرس هسته توابع wp_safe_remote_* را ارائه میدهد که در برابر SSRF محافظت نسبی دارند، اما بسیاری از توسعهدهندگان از نسخههای ناامن wp_remote_* استفاده میکنند. برای مرور کلی امنیت وردپرس، امنیت وردپرس را ببینید.
oEmbed بهعنوان دروازه پنهان
oEmbed یک استاندارد برای جاسازی محتوای خارجی (مانند ویدئوی YouTube یا توییت) است. وردپرس بهطور پیشفرض از این قابلیت استفاده میکند و در پیشخوان، وقتی کاربر یک URL را در ویرایشگر وارد میکند، وردپرس به آن آدرس درخواست میفرستد تا اطلاعات جاسازی را دریافت کند. این رفتار، یک سطح SSRF بالقوه است:
- مهاجم میتواند URL داخلی مانند
http://localhost:8080/adminرا وارد کند. - وردپرس به آن آدرس درخواست میفرستد و پاسخ را پردازش میکند.
- اگر پاسخ حاوی اطلاعات حساس باشد، مهاجم میتواند از آن استفاده کند.
برای غیرفعالسازی oEmbed در صورت عدم نیاز:
remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
remove_action( 'wp_head', 'wp_oembed_add_host_js' );
add_filter( 'embed_oembed_discover', '__return_false' );
remove_filter( 'pre_oembed_result', 'wp_oembed_remote_get' );
add_filter( 'pre_oembed_result', '__return_null' );
البته این کار ممکن است برخی قابلیتهای جاسازی را غیرفعال کند. برای مرور سایر خطاهای پیکربندی، اشتباهات امنیتی رایج در وردپرس را ببینید.
مکانیزم فنی حمله SSRF
یک payload ساده SSRF برای دسترسی به متادیتای ابری AWS:
http://169.254.169.254/latest/meta-data/iam/security-credentials/
اگر سرور روی AWS اجرا شود و افزونهای این URL را بدون اعتبارسنجی پردازش کند، مهاجم میتواند اعتبارنامه IAM را دریافت کند. برای دسترسی به سرویسهای داخلی:
http://internal-redis:6379/
http://localhost:9200/_cat/indices
در این حالت، مهاجم میتواند از سرور قربانی بهعنوان «پروکسی» برای دسترسی به منابع داخلی استفاده کند. نوع پیشرفتهتر SSRF، «Blind SSRF» است که در آن پاسخ به مهاجم بازگردانده نمیشود، اما مهاجم با استفاده از timing attack یا side-channel، اطلاعات را استخراج میکند. برای دیدن نمونههای مشابه از آسیبپذیریهای تزریقی، حمله تزریق کد را ببینید.
نوع دیگر SSRF، «DNS Rebinding» است که در آن مهاجم ابتدا یک دامنه معتبر ثبت میکند و سپس رکورد DNS را به آدرس داخلی تغییر میدهد. این تکنیک، دفاعهای مبتنی بر «بررسی یکباره» را دور میزند.
پیامدهای واقعی SSRF در پروژههای وردپرسی
| سطح | پیامد |
|---|---|
| دسترسی به متادیتا | خواندن اعتبارنامه ابری، توکنهای IAM |
| اسکن شبکه داخلی | شناسایی سرویسهای فعال، نقشهبرداری زیرساخت |
| دسترسی به سرویسهای داخلی | Redis، Elasticsearch، پایگاه داده بدون احراز هویت |
| DoS | ارسال درخواستهای سنگین به سرویسهای حساس |
در پروژهای که بررسی کردیم، یک افزونه همگامسازی از wp_remote_get() برای دریافت داده از سرور خارجی استفاده میکرد و URL را از ورودی کاربر میگرفت. مهاجم میتوانست با ارسال URL داخلی، به سرویس Redis بدون احراز هویت دسترسی پیدا کند و کل کش سایت را پاک کند. برای مرور آسیبپذیریهای مشابه در افزونهها، آسیبپذیری افزونههای وردپرس را ببینید.
دفاع مؤثر در برابر SSRF
دفاع در چند لایه انجام میشود. هیچ لایهای بهتنهایی کافی نیست.
لایه ۱: استفاده از wp_safe_remote_*
وردپرس توابع wp_safe_remote_get() و wp_safe_remote_post() را ارائه میدهد که آدرسهای داخلی را مسدود میکنند:
$response = wp_safe_remote_get( $url, ['timeout' => 5] );
if ( is_wp_error( $response ) ) {
// مدیریت خطا
}
این توابع از wp_http_validate_url() استفاده میکنند که آدرسهای خصوصی (مانند 127.0.0.1، 192.168.*، 10.*) را رد میکند.
لایه ۲: اعتبارسنجی سختگیرانه URL
$allowed_hosts = ['api.example.com', 'cdn.example.com'];
$parsed = wp_parse_url( $url );
if ( ! in_array( $parsed['host'], $allowed_hosts, true ) ) {
wp_die( 'Invalid host' );
}
این «whitelist» مبتنی بر دامنه، مطمئنترین روش است. حتی اگر مهاجم بتواند آدرس را دستکاری کند، فقط دامنههای مجاز پردازش میشوند.
لایه ۳: مسدودسازی آدرسهای داخلی در سطح شبکه
در سطح سرور، میتوانید با iptables یا فایروال، خروج ترافیک به آدرسهای داخلی را محدود کنید:
iptables -A OUTPUT -d 169.254.0.0/16 -j DROP
iptables -A OUTPUT -d 10.0.0.0/8 -j DROP
iptables -A OUTPUT -d 172.16.0.0/12 -j DROP
iptables -A OUTPUT -d 192.168.0.0/16 -j DROP
این لایه، دفاع نهایی است. حتی اگر کد آسیبپذیر باشد، سرور نمیتواند به منابع داخلی درخواست بفرستد.
لایه ۴: محدودسازی پاسخ
اندازه پاسخ و نوع محتوا را محدود کنید:
$response = wp_safe_remote_get( $url, [
'timeout' => 5,
'redirection' => 0,
] );
$content_type = wp_remote_retrieve_header( $response, 'content-type' );
if ( strpos( $content_type, 'text/html' ) === false ) {
wp_die( 'Invalid content type' );
}
این کار، حمله از طریق redirect و محتوای غیرمنتظره را دشوار میکند. برای درک عمیقتر اصول امنیتی، اصول امنیت وب را ببینید.
کاربرد wp_safe_remote_* در عمل
تفاوت wp_remote_get() و wp_safe_remote_get() در یک فیلتر کلیدی است: http_request_host_is_external. تابع امن، آدرسهای خصوصی را قبل از ارسال درخواست رد میکند. اما این محافظت کامل نیست:
- اگر دامنهای از DNS Rebinding استفاده کند، ممکن است بررسی اولیه رد شود اما درخواست واقعی به آدرس داخلی برود.
- برخی توابع وردپرس، پارامتر
reject_unsafe_urlsرا نادیده میگیرند. - افزونهها میتوانند فیلتر را دور بزنند.
بنابراین، wp_safe_remote_* یک لایه دفاعی است، نه یک راهحل کامل. برای مرور ساختار REST در وردپرس، استفاده از REST API در وردپرس را ببینید.
اشتباهات رایج در دفع SSRF
- اتکای صرف به
wp_safe_remote_*: این توابع در برابر DNS Rebinding آسیبپذیرند. - استفاده از blacklist بهجای whitelist: blacklist همیشه دور زده میشود.
- نادیده گرفتن redirect: مهاجم میتواند از redirect برای دور زدن بررسی اولیه استفاده کند.
- فراموش کردن oEmbed: این قابلیت بهطور پیشفرض فعال است.
- اعتماد به افزونههای شخصثالث: بسیاری از افزونهها از
wp_remote_get()بدون اعتبارسنجی استفاده میکنند. - عدم محدودسازی اندازه پاسخ: حمله DoS از طریق پاسخهای بزرگ.
- عدم مسدودسازی در سطح شبکه: دفاع فقط در لایه کد کافی نیست.
برای مرور خطاهای مشابه در پیکربندی امنیتی، اشتباهات امنیتی رایج در وردپرس را ببینید.
پرسشهای پرتکرار درباره SSRF Prevention
آیا وردپرس هسته در برابر SSRF آسیبپذیر است؟ هسته از wp_safe_remote_* در بسیاری از نقاط استفاده میکند، اما برخی بخشها مانند oEmbed همچنان سطح حمله دارند. برای مرور کلی، امنیت وردپرس را ببینید.
آیا غیرفعال کردن oEmbed کافی است؟ نه، زیرا افزونهها و کتابخانههای دیگر نیز درخواست HTTP ارسال میکنند.
آیا افزونههای امنیتی وردپرس SSRF را دفع میکنند؟ برخی از آنها WAF دارند که میتواند payloadهای شناختهشده را مسدود کند، اما دفاع اصلی باید در لایه کد و شبکه باشد. برای مرور گزینهها، بهترین افزونههای امنیتی وردپرس را ببینید.
چطور بفهمم سایت من در برابر SSRF آسیبپذیر است؟ ابزارهای تست خودکار مانند Burp Suite و OWASP ZAP میتوانند کمک کنند. برای مرور گزینهها، اسکنرهای آسیبپذیری وب را ببینید.
آیا SSRF فقط سایتهای بزرگ را تهدید میکند؟ نه، هر سایتی که درخواست HTTP بر اساس ورودی کاربر ارسال کند، میتواند هدف باشد. حتی سایتهای کوچک نیز قربانی میشوند.
برای مطالعه بیشتر درباره این آسیبپذیری، صفحه Server-side request forgery در ویکیپدیا مفید است.
خط پایان
SSRF Prevention یکی از آن لایههای امنیتی است که در سایه XSS و SQL Injection کمتر دیده میشود، اما پیامدهای آن میتواند از نشت اعتبارنامه ابری تا نفوذ کامل به زیرساخت متغیر باشد. در بستر وردپرس، مسیرهای ورود متعدد — از oEmbed تا افزونههای همگامسازی — سطح حمله را بزرگ میکند. دفاع مؤثر نیازمند استفاده از wp_safe_remote_*، اعتبارسنجی سختگیرانه URL، مسدودسازی آدرسهای داخلی در سطح شبکه، و محدودسازی پاسخ است. اگر سایت شما درخواست HTTP بر اساس ورودی کاربر ارسال میکند، همین امروز بازبینی کنید.
اگر در پروژهای با SSRF روبهرو شدهاید یا راهکار دفاعی متفاوتی پیاده کردهاید، تجربه خود را در دیدگاهها بنویسید؛ بهخصوص اگر افزونه یا کتابخانه خاصی عامل بوده، این اطلاعات برای خواننده بعدی بسیار ارزشمند است.