با Fetch Metadata از منابع خود در برابر حملات وب محافظت کنید

از نشت اطلاعات CSRF، XSSI و منبع متقابل جلوگیری کنید.

بسیاری از برنامه‌های کاربردی وب در برابر حملات متقاطع مانند جعل درخواست بین سایتی (CSRF)، گنجاندن اسکریپت متقابل سایت (XSSI)، حملات زمان‌بندی، نشت اطلاعات از مبدأ متقابل یا حملات احتمالی اجرای کانال جانبی ( Spectre ) آسیب‌پذیر هستند.

هدرهای درخواست فراداده واکشی به شما این امکان را می دهد که یک مکانیسم قوی دفاعی در عمق - یک خط مشی جداسازی منابع - برای محافظت از برنامه خود در برابر این حملات متقابل متداول ایجاد کنید.

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

سازگاری مرورگر

سرصفحه‌های درخواست فراداده واکشی در همه موتورهای مرورگر مدرن پشتیبانی می‌شوند.

پشتیبانی مرورگر

  • کروم: 76.
  • لبه: 79.
  • فایرفاکس: 90.
  • سافاری: 16.4.

منبع

پس زمینه

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

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

معرفی Fetch Metadata

هدرهای درخواست فراداده Fetch یک ویژگی امنیتی جدید پلتفرم وب است که برای کمک به سرورها در دفاع از خود در برابر حملات متقابل طراحی شده است. با ارائه اطلاعات در مورد زمینه یک درخواست HTTP در مجموعه‌ای از هدرهای Sec-Fetch-* ، آنها به سرور پاسخ‌دهنده اجازه می‌دهند تا قبل از پردازش درخواست، سیاست‌های امنیتی را اعمال کند. این به توسعه‌دهندگان اجازه می‌دهد تا بر اساس روشی که درخواستی ارائه شده و زمینه استفاده از آن را بپذیرند یا رد کنند، و این امکان را فراهم می‌آورد که فقط به درخواست‌های قانونی ارائه شده توسط برنامه خودشان پاسخ دهند.

همان منبع
درخواست‌هایی که از سایت‌هایی که توسط سرور خود شما ارائه می‌شوند (همان منبع) به کار خود ادامه می‌دهند. درخواست واکشی از https://site.example برای منبع https://site.example/foo.json در جاوا اسکریپت باعث می شود که مرورگر سرصفحه درخواست HTTP "Sec Fetch-Site: same-origin" را ارسال کند.
متقابل سایت
درخواست‌های مخرب بین سایتی را می‌توان توسط سرور رد کرد زیرا زمینه اضافی در درخواست HTTP ارائه شده توسط هدرهای Sec-Fetch-* وجود دارد. تصویری در https://evil.example که ویژگی src عنصر img را روی "https://site.example/foo.json" تنظیم کرده است باعث می شود مرورگر سرصفحه درخواست HTTP را "Sec-Fetch-Site" ارسال کند: متقابل سایت'.

Sec-Fetch-Site

پشتیبانی مرورگر

  • کروم: 76.
  • لبه: 79.
  • فایرفاکس: 90.
  • سافاری: 16.4.

منبع

Sec-Fetch-Site به سرور می گوید که کدام سایت درخواست را ارسال کرده است. مرورگر این مقدار را به یکی از موارد زیر تنظیم می کند:

  • same-origin ، اگر درخواست توسط برنامه شخصی شما انجام شده باشد (به عنوان مثال site.example )
  • same-site ، اگر درخواست توسط یک زیر دامنه سایت شما انجام شده باشد (به عنوان مثال bar.site.example )
  • none ، اگر درخواست صریحاً ناشی از تعامل کاربر با عامل کاربر باشد (مثلاً کلیک کردن روی یک نشانک)
  • cross-site ، اگر درخواست توسط وب سایت دیگری ارسال شده باشد (به عنوان مثال evil.example )

Sec-Fetch-Mode

پشتیبانی مرورگر

  • کروم: 76.
  • لبه: 79.
  • فایرفاکس: 90.
  • سافاری: 16.4.

منبع

Sec-Fetch-Mode حالت درخواست را نشان می دهد. این تقریباً با نوع درخواست مطابقت دارد و به شما امکان می دهد بارهای منبع را از درخواست های ناوبری تشخیص دهید. به عنوان مثال، مقصد navigate یک درخواست ناوبری سطح بالا را نشان می دهد در حالی که no-cors درخواست های منبع مانند بارگیری یک تصویر را نشان می دهد.

Sec-Fetch-Dest

پشتیبانی مرورگر

  • کروم: 80.
  • لبه: 80.
  • فایرفاکس: 90.
  • سافاری: 16.4.

منبع

Sec-Fetch-Dest مقصد درخواست را نشان می دهد (مثلاً اگر یک script یا یک تگ img باعث درخواست منبع توسط مرورگر شود).

نحوه استفاده از Fetch Metadata برای محافظت در برابر حملات متقاطع

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

اجرای سیاست جداسازی منابع

یک خط مشی جداسازی منابع از درخواست منابع شما توسط وب سایت های خارجی جلوگیری می کند. مسدود کردن چنین ترافیکی آسیب‌پذیری‌های رایج وب بین‌سایتی مانند CSRF، XSSI، حملات زمان‌بندی و نشت اطلاعات از مبدا متقابل را کاهش می‌دهد. این خط‌مشی را می‌توان برای تمام نقاط پایانی برنامه‌تان فعال کرد و به همه درخواست‌های منبعی که از برنامه خودتان و همچنین پیمایش مستقیم (از طریق درخواست HTTP GET ) می‌آیند، اجازه می‌دهد. نقاط پایانی که قرار است در یک زمینه بین سایتی بارگیری شوند (مثلاً نقاط پایانی بارگیری شده با استفاده از CORS) می توانند از این منطق خارج شوند.

مرحله 1: به درخواست‌های مرورگرهایی که فراداده واکشی را ارسال نمی‌کنند، اجازه دهید

از آنجایی که همه مرورگرها از Fetch Metadata پشتیبانی نمی‌کنند، باید با بررسی وجود sec-fetch-site به درخواست‌هایی که سرصفحه‌های Sec-Fetch-* را تنظیم نمی‌کنند اجازه دهید.

if not req['sec-fetch-site']:
  return True  # Allow this request

مرحله 2: درخواست‌های ایجاد شده توسط همان سایت و مرورگر را مجاز کنید

هر درخواستی که از یک زمینه متقاطع (مانند evil.example ) منشأ نمی گیرد، مجاز خواهد بود. به ویژه، اینها درخواست هایی هستند که:

  • از برنامه خود منشأ بگیرید (مثلاً درخواستی با همان منبع که site.example درخواست site.example/foo.json همیشه مجاز خواهد بود).
  • از زیر دامنه های خود منشاء بگیرید.
  • به صراحت توسط تعامل کاربر با عامل کاربر ایجاد می شوند (مثلاً پیمایش مستقیم یا با کلیک کردن روی یک نشانک و غیره).
if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'):
  return True  # Allow this request

مرحله 3: به پیمایش ساده سطح بالا و iframing اجازه دهید

برای اطمینان از اینکه سایت شما همچنان می‌تواند از سایت‌های دیگر پیوند داشته باشد، باید به ناوبری ساده ( HTTP GET ) در سطح بالا اجازه دهید.

if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET'
  # <object> and <embed> send navigation requests, which we disallow.
  and req['sec-fetch-dest'] not in ('object', 'embed'):
    return True  # Allow this request

مرحله 4: انصراف از نقاط پایانی که برای ارائه ترافیک بین سایتی هستند (اختیاری)

در برخی موارد، برنامه شما ممکن است منابعی را ارائه دهد که قرار است از طریق سایت بارگیری شوند. این منابع باید بر اساس هر مسیر یا نقطه پایانی معاف شوند. نمونه هایی از این نقاط پایانی عبارتند از:

  • نقاط پایانی برای دسترسی به مبدأ متقابل: اگر برنامه شما در حال ارائه نقاط پایانی است که CORS فعال هستند، باید صریحاً آنها را از جداسازی منابع انصراف دهید تا اطمینان حاصل کنید که درخواست‌های بین سایتی برای این نقاط پایانی همچنان امکان‌پذیر است.
  • منابع عمومی (مثلاً تصاویر، سبک‌ها و غیره): هر منبع عمومی و احراز هویت نشده ای که باید از سایت‌های دیگر قابل بارگیری باشد نیز می‌تواند مستثنی شود.
if req.path in ('/my_CORS_endpoint', '/favicon.png'):
  return True

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

هر درخواست دیگر بین سایتی توسط این سیاست جداسازی منابع رد می شود و بنابراین از برنامه شما در برابر حملات متداول بین سایتی محافظت می کند.

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

# Reject cross-origin requests to protect from CSRF, XSSI, and other bugs
def allow_request(req):
  # Allow requests from browsers which don't send Fetch Metadata
  if not req['sec-fetch-site']:
    return True

  # Allow same-site and browser-initiated requests
  if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'):
    return True

  # Allow simple top-level navigations except <object> and <embed>
  if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET'
    and req['sec-fetch-dest'] not in ('object', 'embed'):
      return True

  # [OPTIONAL] Exempt paths/endpoints meant to be served cross-origin.
  if req.path in ('/my_CORS_endpoint', '/favicon.png'):
    return True

  # Reject all other requests that are cross-site and not navigational
  return False

استقرار یک سیاست جداسازی منابع

  1. ماژولی مانند قطعه کد را از بالا نصب کنید تا وارد شوید و نحوه رفتار سایت خود را نظارت کنید و مطمئن شوید که محدودیت ها بر ترافیک قانونی تأثیر نمی گذارد.
  2. با معافیت از نقاط پایانی متقابل قانونی، تخلفات احتمالی را برطرف کنید.
  3. با حذف درخواست‌های ناسازگار، خط‌مشی را اجرا کنید.

شناسایی و رفع تخلفات خط مشی

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

از تجربه ما در ارائه خط‌مشی جداسازی منابع فراداده واکشی در Google، اکثر برنامه‌ها به طور پیش‌فرض با چنین خط‌مشی سازگار هستند و به ندرت به نقاط پایانی مستثنی برای اجازه دادن به ترافیک بین سایتی نیاز دارند.

اجرای سیاست جداسازی منابع

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

در ادامه مطلب