Application Security

محافظت از ابر: راهنمای جامع برای ایمن‌سازی SSRF در معماری‌های مدرن

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

درک منظره تهدیدات

SSRF زمانی رخ می‌دهد که یک برنامه یک URL را به عنوان ورودی کاربر می‌پذیرد و سپس بدون اعتبارسنجی کافی، آن URL را دریافت می‌کند. برخلاف جعل درخواست سمت کلاینت که در آن مرورگر کاربر درخواست را آغاز می‌کند، SSRF از مرز اعتماد سرور سوءاستفاده می‌کند. در معماری‌های مبتنی بر ابر، این موضوع به ویژه خطرناک است. ارائه‌دهندگان ابر، نقاط پایانی متادیتا (مانند 169.254.169.254 برای AWS) را در دسترس قرار می‌دهند که حاوی اعتبارنامه‌های حساس هستند. اگر یک مهاجم بتواند یک حمله SSRF را فعال کند، می‌تواند این اعتبارنامه‌ها را بازیابی کرده، سطح دسترسی را ارتقا دهد و کل زیرساخت را به خطر بیندازد.

سطح حمله بسیار گسترده است. این شامل سرویس‌های پردازش تصویر، وب‌هوک‌ها، ابزارهای همگام‌سازی داده و دروازه‌های API می‌شود. یک سناریوی معمول شامل یک ویژگی آپلود تصویر است که در آن سرور تصویر را از یک URL ارائه شده دریافت می‌کند تا فرمت آن را اعتبارسنجی کند. بدون کنترل‌های سخت‌گیرانه، یک مهاجم می‌تواند URLی را که به سرویس متادیتای داخلی یا پنل مدیریت localhost اشاره دارد، ارائه دهد.

دفاع در عمق: راهبردهای اعتبارسنجی و فیلترینگ

ایمن‌سازی SSRF نیازمند رویکردی چندلایه است. تکیه بر یک روش واحد، مانند لیست سیاه کردن، دستورالعملی برای فاجعه است. به جای آن، فلسفه «رد پیش‌فرض» را در پیش بگیرید. در اینجا ستون‌های اصلی یک دفاع مستحکم آورده شده است:

1. اعتبارسنجی سخت‌گیرانه ورودی

خط اول دفاع، اعتبارسنجی فرمت ورودی است. اطمینان حاصل کنید که تنها پروتکل‌های تأیید شده (معمولاً HTTP و HTTPS) پذیرفته می‌شوند. سایر پروتکل‌هایی مانند FTP، GOPHER یا JAR را رد کنید، زیرا این‌ها اغلب می‌توانند منجر به اجرای کد از راه دور (RCE) در کتابخانه‌های قدیمی شوند.

function validateUrl(urlString) {
  try {
    const url = new URL(urlString);
    if (!['http:', 'https:'].includes(url.protocol)) {
      throw new Error('پروتکل مجاز نیست');
    }
    // بررسی‌های اضافی برای IP و محدوده‌های CIDR باید در ادامه انجام شود
    return true;
  } catch (e) {
    return false;
  }
}

2. رزولوشن آدرس IP و لیست سیاه کردن

حتی اگر پروتکل ایمن باشد، آدرس IP مقصد باید با دقت بررسی شود. مهاجمان اغلب از حروف‌نویسی IPv4/IPv6، نمادگذاری CIDR یا کاراکترهای کدگذاری شده برای دور زدن تطبیق رشته‌ای ساده استفاده می‌کنند. موثرترین روش، رزولوشن نام میزبان به یک آدرس IP خارج از شبکه برنامه قبل از ارسال درخواست است.

یک تابع رزولور پیاده‌سازی کنید که IP حاصل را با محدوده‌های خطرناک شناخته شده مقایسه کند: شبکه‌های محلی خصوصی (10.0.0.0/8، 192.168.0.0/16)، آدرس‌های لینک-لوکال (169.254.0.0/16) و آدرس‌های لوپ‌بک (127.0.0.1).

const ipaddr = require('ipaddr.js');

function isIpSafe(ip) {
  try {
    let addr = ipaddr.parse(ip);
    // مدیریت نگاشت IPv6 به IPv4
    if (addr.kind() === 'ipv6' && addr.isIPv4MappedAddress()) {
      addr = addr.toIPv4Address();
    }
    
    return addr.range() === 'unicast'; // اجازه فقط آدرس‌های عمومی و یونیکاست
  } catch (e) {
    return false;
  }
}

3. کاهش حملات بازبندی DNS

حملات می‌توانند پیچیده باشند و از بازبندی DNS برای رزولوشن یک نام میزبان به یک IP داخلی در ابتدا (برای عبور از اعتبارسنجی) و سپس تغییر آن به یک IP عمومی در طول درخواست HTTP، یا برعکس، استفاده کنند. برای مقابله با این موضوع، برنامه باید اطمینان حاصل کند که آدرس IP رزولوشن شده در زمان اعتبارسنجی، همان آدرسی است که برای اتصال واقعی استفاده می‌شود. برخی از کلاینت‌های HTTP ایمن گزینه‌هایی را برای غیرفعال کردن رزولوشن DNS تا زمانی که درخواست تأیید شود، ارائه می‌دهند.

4. جداسازی شبکه و فیلترینگ خروجی

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

مثال عملی: ایمن‌سازی یک دریافت‌کننده تصویر

سناریویی را در نظر بگیرید که در آن یک سرور تصویری را از یک URL ارائه شده توسط کاربر دریافت می‌کند. در زیر الگویی آورده شده است که شامل تجزیه URL، اعتبارسنجی پروتکل و بررسی IP است.

const https = require('https');
const { URL } = require('url');
const ipaddr = require('ipaddr.js');

async function secureFetchImage(userProvidedUrl) {
  let parsedUrl;
  try {
    parsedUrl = new URL(userProvidedUrl);
  } catch (e) {
    throw new Error('فرمت URL نامعتبر است');
  }

  // 1. بررسی پروتکل
  if (!['http:', 'https:'].includes(parsedUrl.protocol)) {
    throw new Error('فقط پروتکل‌های HTTP و HTTPS مجاز هستند');
  }

  // 2. رزولوشن و اعتبارسنجی IP (برای نمایش ساده شده است)
  // در محیط تولید، از یک کتابخانه DNS برای رزولوشن نام میزبان استفاده کنید
  const hostname = parsedUrl.hostname;
  const safeIp = resolveHost(hostname); // فرض بر این است که این تابع DNS را رزولوشن می‌کند
  
  if (!isIpSafe(safeIp)) {
    throw new Error('دسترسی به IPهای داخلی یا رزرو شده ممنوع است');
  }

  // 3. انجام درخواست با یک تایم‌اوت کوتاه
  return new Promise((resolve, reject) => {
    const req = https.get(userProvidedUrl, { timeout: 5000 }, (res) => {
      // مدیریت پاسخ
      resolve(res);
    });
    req.on('error', reject);
  });
}

نتیجه‌گیری

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

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

Share: