آن فایل PHP که ناگهان در uploads ظاهر شد

چند سال پیش، در یکی از پرونده‌های پاک‌سازی، فایلی با نام innocuous-looking.php در پوشهٔ uploads پیدا کردم. اندازه‌اش کوچک بود و به‌نظر بی‌خطر می‌رسید، اما وقتی محتوایش را باز کردم، یک کد مخرب بود که به مهاجم اجازه می‌داد هر فایلی را روی سرور آپلود یا اجرا کند. آن روز برای من روشن شد که تزریق کد یکی از خطرناک‌ترین حملات سایبری است، چون به مهاجم کنترل کامل سرور را می‌دهد. در این مقاله، همه‌چیز را دربارهٔ این حمله مرور می‌کنیم. اگر با مفاهیم پایه آشنا نیستید، پیشنهاد می‌کنم ابتدا حملات سایبری چیست و چه انواعی دارد را بخوانید.

حمله تزریق کد دقیقاً چیست؟

حمله تزریق کد یا Code Injection به هر حمله‌ای گفته می‌شود که در آن مهاجم کد مخرب را به یک برنامه تزریق می‌کند و آن کد در سرور اجرا می‌شود. برخلاف XSS که کد در مرورگر کاربر اجرا می‌شود، در Code Injection کد در سرور و توسط خود برنامه اجرا می‌شود.

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

حمله تزریق کد در برابر سایر حملات تزریق

حمله تزریق کد با سایر حملات تزریق تفاوت دارد:

  • SQL Injection: کد مخرب در دیتابیس اجرا می‌شود. راهنما در SQL Injection چیست و چگونه جلوگیری کنیم آمده است.
  • XSS: کد مخرب در مرورگر کاربر اجرا می‌شود. راهنما در حملات XSS چیست و چگونه دفع می‌شود آمده است.
  • Code Injection: کد مخرب در سرور اجرا می‌شود. این نوع خطرناک‌تر است، چون کنترل کامل سرور را به مهاجم می‌دهد.
  • Command Injection: دستورات سیستمعامل در سرور اجرا می‌شود. زیرمجموعه‌ای از Code Injection است.
  • LDAP Injection: در سرویس‌های دایرکتوری اجرا می‌شود.
  • XPath Injection: در کوئری‌های XML اجرا می‌شود.
  • Email Header Injection: در هدرهای ایمیل اجرا می‌شود.

هرکدام از این حملات، نیازمند راهکار دفاعی خاص خودشان هستند.

مکانیزم حمله تزریق کد

حمله تزریق کد در چند مرحله انجام می‌شود:

  • گام اول — شناسایی نقطه ورود: مهاجم نقاطی که ورودی کاربر دریافت می‌کنند را بررسی می‌کند. این می‌تواند فرم‌ها، پارامترهای URL، APIها، فایل‌های آپلودشده یا هدرهای HTTP باشد.
  • گام دوم — تزریق کد: مهاجم کد مخرب را از طریق نقطه ورود تزریق می‌کند.
  • گام سوم — اجرا: اگر برنامه کد را بدون پاک‌سازی اجرا کند، کد مخرب در سرور اجرا می‌شود.
  • گام چهارم — بهره‌برداری: مهاجم از کد اجراشده برای اهداف خود استفاده می‌کند.
  • گام پنجم — پاک‌سازی ردپا: مهاجم تلاش می‌کند ردپای خود را پاک کند.

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

انواع حمله تزریق کد

حمله تزریق کد در چند نوع اصلی انجام می‌شود:

  • SQL Injection: تزریق کوئری SQL در ورودی‌ها برای دسترسی به دیتابیس.
  • Command Injection: تزریق دستورات سیستمعامل در ورودی‌ها. این نوع بسیار خطرناک است چون کنترل کامل سرور را به مهاجم می‌دهد.
  • LDAP Injection: تزریق کوئری LDAP برای دسترسی به سرویس‌های دایرکتوری.
  • XPath Injection: تزریق کوئری XPath در برنامه‌هایی که با XML کار می‌کنند.
  • Email Header Injection: تزریق در هدرهای ایمیل برای ارسال ایمیل‌های اسپم.
  • PHP Object Injection: سوءاستفاده از unserialize در PHP برای اجرای کد.
  • Template Injection: تزریق کد در موتورهای قالب مثل Twig یا Jinja2.
  • Server-Side JavaScript Injection: تزریق کد در محیط‌های Node.js.
  • XML External Entity (XXE): تزریق موجودیت‌های خارجی در پردازش XML.
  • Expression Language Injection: تزریق کد در زبان‌های Expression مثل SpEL یا OGNL.

هرکدام از این انواع، نیازمند راهکار دفاعی متفاوتی هستند.

نشانه‌های حمله تزریق کد

شناخت نشانه‌های حمله تزریق کد به واکنش سریع کمک می‌کند:

  • فایل‌های ناشناس در سرور: فایل‌های PHP یا اسکریپت‌های ناشناس در پوشه‌های غیرمعمول مثل uploads.
  • رفتار غیرعادی سرور: مصرف ناگهانی CPU یا RAM، درخواست‌های غیرعادی، قطع و وصل شدن سرویس.
  • تغییرات غیرمجاز در فایل‌ها: تغییرات در فایل‌های هسته، قالب یا افزونه‌ها.
  • کاربران ناشناس: ظهور کاربران ناشناس در فهرست کاربران.
  • ایمیل‌های اسپم از سرور: اگر سرور شما برای ارسال اسپم استفاده می‌شود.
  • هشدار هاست: هشدار مصرف منابع یا فعالیت مشکوک.
  • لاگ‌های غیرعادی: الگوهای غیرعادی در لاگ‌های سرور.
  • کندی سایت: کندی ناگهانی سایت بدون دلیل واضح.

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

راهکارهای دفاع در برابر تزریق کد

دفاع در برابر تزریق کد نیازمند رویکردی چندلایه‌ای است:

  • اعتبارسنجی ورودی: تمام ورودی‌های کاربر باید اعتبارسنجی شوند. هر ورودی باید فقط شامل کاراکترهای مجاز باشد.
  • پاک‌سازی ورودی: تمام ورودی‌ها باید پاک‌سازی شوند تا کاراکترهای مخرب حذف شوند.
  • Prepared Statements: برای جلوگیری از SQL Injection، همیشه از Prepared Statements استفاده کنید.
  • اجتناب از eval و exec: هرگز از توابعی مثل eval، exec، system و shell_exec با ورودی کاربر استفاده نکنید.
  • محدودسازی دسترسی: دسترسی سرور، دیتابیس و فایل‌ها باید بر اساس اصل کمترین امتیاز تنظیم شوند.
  • اجتناب از unserialize: در PHP، هرگز از unserialize با ورودی کاربر استفاده نکنید. از json_decode استفاده کنید.
  • پایش و لاگ: لاگ‌ها و رفتار سرور را به‌طور مداوم پایش کنید.
  • به‌روزرسانی سریع: تمام نرم‌افزارها را به‌روز نگه دارید.
  • فایروال و WAF: فایروال‌های نرم‌افزاری و WAF می‌توانند درخواست‌های مخرب را مسدود کنند.
  • اجرای کد در محیط محدود: اگر مجبور به اجرای کد از ورودی هستید، آن را در محیط محدود مثل sandbox اجرا کنید.
  • Server Hardening: سرور را با اصول امنیتی سخت‌سازی کنید. راهنما در چگونه امنیت سرور را افزایش دهیم آمده است.

ترکیب این لایه‌ها، احتمال موفقیت حمله تزریق کد را به‌شدت کاهش می‌دهد.

تزریق کد در وردپرس

در سایت‌های وردپرسی، تزریق کد می‌تواند از چند مسیر رخ دهد:

  • افزونه‌های ناامن: افزونه‌هایی که ورودی کاربر را بدون پاک‌سازی پردازش می‌کنند.
  • قالب‌های ناشناس: قالب‌هایی که کد مخرب دارند یا فایل‌های PHP را بدون اعتبارسنجی بارگذاری می‌کنند.
  • افزونه‌های رهاشده: افزونه‌هایی که مدتی طولانی به‌روزرسانی نشده‌اند.
  • فرم‌ها و APIها: اگر فرم یا API وردپرس ورودی کاربر را بدون پاک‌سازی پردازش کند.
  • پوشهٔ uploads: اگر پوشهٔ uploads بتواند فایل‌های PHP را اجرا کند، مهاجم می‌تواند کد مخرب را در آن آپلود کند.
  • آپلود فایل ناامن: اگر فرم آپلود، نوع فایل را اعتبارسنجی نکند، مهاجم می‌تواند فایل PHP آپلود کند.
  • شورت‌کدها: اگر شورت‌کد از ورودی کاربر استفاده کند.
  • AJAX Handlers: اگر handlerهای AJAX ورودی را پاک‌سازی نکنند.
  • REST API Endpoints: اگر endpoints ورودی را پاک‌سازی نکنند.

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

تزریق کد در PHP

PHP یکی از زبان‌هایی است که بیشترین آسیب‌پذیری تزریق کد را دارد. الگوهای رایج کد آسیب‌پذیر:

  • eval: eval($_GET["code"]) — هرگز از eval با ورودی کاربر استفاده نکنید.
  • exec و shell_exec: shell_exec($_GET["cmd"]) — هرگز ورودی کاربر را به توابع سیستمعامل پاس ندهید.
  • include با ورودی کاربر: include($_GET["page"].".php") — این نوع به RFI و LFI منجر می‌شود. راهنما در آسیب‌پذیری RFI و LFI چه تفاوتی دارند آمده است.
  • preg_replace با /e: الگوی قدیمی که در PHP 7 حذف شده است.
  • create_function: تابعی که در PHP 7.2 منسوخ و در 8 حذف شده است.
  • unserialize: unserialize($_GET["data"]) — می‌تواند به Object Injection منجر شود.
  • فراخوانی متغیر تابع: $_GET["func"]() — اجازه اجرای هر تابعی را می‌دهد.

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

تزریق کد در Node.js

Node.js هم در برابر تزریق کد آسیب‌پذیر است. الگوهای رایج:

  • eval: eval(req.query.code) — بسیار خطرناک است.
  • child_process.exec: exec(req.query.cmd) — می‌تواند به Command Injection منجر شود.
  • new Function: معادل eval در Node.js است.
  • vm.runInNewContext: اجرای کد در محیط محدود، اما اگر درست پیکربندی نشود، خطرناک است.
  • require با ورودی کاربر: می‌تواند به اجرای هر ماژولی منجر شود.

در Node.js، همیشه باید ورودی‌ها را اعتبارسنجی و پاک‌سازی کنید و از توابع اجرای کد پرهیز کنید.

## تزریق کد در Python

در Python، تزریق کد می‌تواند از چند مسیر رخ دهد:

  • eval و exec: eval(input()) یا exec(input()) — بسیار خطرناک است.
  • os.system و subprocess: os.system(cmd) یا subprocess.run(cmd, shell=True) — می‌تواند به Command Injection منجر شود.
  • pickle.loads: مشابه unserialize در PHP، می‌تواند کد اجرا کند.
  • yaml.load: در نسخه‌های قدیمی PyYAML، می‌تواند کد اجرا کند. از safe_load استفاده کنید.
  • فراخوانی متغیر: getattr(module, name)() اگر name از ورودی کاربر باشد، خطرناک است.
  • Jinja2 Template Injection: اگر ورودی کاربر در قالب قرار گیرد، می‌تواند کد اجرا کند.

راهنمای Python در آموزش پایتون از صفر آمده است.

پاک‌سازی ورودی: پایه دفاع

پاک‌سازی ورودی، پایه دفاع در برابر تزریق کد است. اصول کلی:

  • Whitelist: به‌جای مسدودسازی ورودی‌های مخرب، فقط ورودی‌های مجاز را بپذیرید.
  • Type Validation: ورودی‌ها را بر اساس نوع مورد انتظار بررسی کنید.
  • Length Limitation: طول ورودی‌ها را محدود کنید.
  • Character Filtering: کاراکترهای غیرمجاز را حذف کنید.
  • Encoding: ورودی‌ها را به‌درستی encode کنید.
  • Escaping: در جایگاه‌های مناسب، از escape استفاده کنید.
  • Sanitization: توابع پاک‌سازی مناسب را استفاده کنید.
  • Regular Expressions: برای اعتبارسنجی الگوها از regex استفاده کنید.

در وردپرس، توابعی مثل sanitize_text_field، esc_html، esc_attr، esc_url و wp_kses وجود دارند که همین کار را انجام می‌دهند.

ابزارهای تشخیص و پیشگیری

ابزارهای مفید برای تشخیص و پیشگیری از تزریق کد:

  • Static Analysis Tools: تحلیل کد بدون اجرا. مثال: SonarQube، Snyk Code، Semgrep.
  • DAST: تحلیل برنامه در حال اجرا. مثال: OWASP ZAP، Burp Suite.
  • SAST + DAST: ترکیب هر دو برای پوشش کامل.
  • WAF: فایروال برنامه وب برای مسدودسازی درخواست‌های مخرب.
  • RASP: حفاظت در زمان اجرا. مثال: Contrast Security.
  • Fuzzing Tools: ارسال ورودی‌های تصادفی برای کشف آسیب‌پذیری.
  • Dependency Scanners: بررسی آسیب‌پذیری در کتابخانه‌ها. مثال: OWASP Dependency-Check.

مستندات ویکی‌پدیا در مورد Code injection اطلاعات فنی کاملی ارائه می‌دهد.

پرسش‌های پرتکرار دربارهٔ حمله تزریق کد

آیا تزریق کد فقط در PHP رخ می‌دهد؟ خیر. تزریق کد در هر زبان برنامه‌نویسی ممکن است. PHP و Node.js بیشترین آسیب‌پذیری را دارند، اما Python، Ruby، Java و سایر زبان‌ها هم در معرض خطر هستند.

آیا تزریق کد همیشه به نفوذ کامل منجر می‌شود؟ بستگی به نوع حمله دارد. Command Injection معمولاً کنترل کامل سرور را به مهاجم می‌دهد، در حالی که LDAP Injection محدودتر است.

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

آیا افزونهٔ امنیتی به‌تنهایی کافی است؟ خیر. افزونهٔ امنیتی می‌تواند برخی حملات را مسدود کند، اما اساس دفاع در کد سایت و پیکربندی صحیح است.

آیا تزریق کد می‌تواند از طریق API رخ دهد؟ بله. APIها یکی از رایج‌ترین مسیرهای تزریق کد در سال‌های اخیر هستند. راهنما در امنیت API در وب آمده است.

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

سخن آخر: پیشگیری، بهترین دفاع

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