کلیدهای عبور درون iframeها

برای ارائه احراز هویت روان و درون متنی در چندین دامنه، سازمان‌ها اغلب صفحات ورود به سیستم را درون iframeها جاسازی می‌کنند. با این حال، بارگذاری زمینه‌های احراز هویت درون فریم‌های شخص ثالث، کاربران را در معرض تهدیدات بحرانی مانند clickjacking (اصلاح رابط کاربری) و ایجاد اعتبارنامه غیرمجاز قرار می‌دهد. برای کاهش این خطرات، مرورگرها به طور پیش‌فرض WebAuthn را در iframeهای بین مبدا غیرفعال می‌کنند. برداشتن ایمن این محدودیت نیاز به پروتکل‌های فعال و دفاعی عمیق دارد.

شناسایی مدل‌های تهدید

قبل از فعال کردن کلیدهای عبور (WebAuthn) در داخل زیرفریم‌ها، سناریوهای سوءاستفاده‌ای را که در برابر آنها از خود دفاع می‌کنید، درک کنید:

  • ردیابی با استفاده از تزریق iframe مخفی: یک مهاجم با استفاده از یک تبلیغ یا ویجت در یک سایت معتبر، یک درخواست WebAuthn را از دامنه خود فعال می‌کند و کاربران را فریب می‌دهد تا بدون دیدن متن، کلید عبور را تأیید کنند. این کار هویت کاربر را به یک حساب کاربری تحت کنترل مهاجم متصل می‌کند تا داده‌ها را جمع‌آوری کند.
  • همپوشانی بصری و سرقت کلیک (اصلاح رابط کاربری): یک صفحه والد مخرب، iframe احراز هویت را با استفاده از CSS استاندارد نامرئی می‌کند و یک عنصر رابط کاربری جعلی را برای سرقت کلیکی که جریان احراز هویت را فعال می‌کند، پوشش می‌دهد. اگر کاربر سهواً درخواست را تکمیل کند، این امر می‌تواند منجر به ربودن جلسه یا اقدامات غیرمجاز اجباری شود.

برای مقابله با این تهدیدها، این بهترین شیوه‌ها را دنبال کنید:

برای سند سطح بالا (فریم بالا):

برای سند جاسازی‌شده (iframe):

برای هر دو سند:

فعال کردن واگذاری اختیار با استفاده از سیاست مجوزها

مرورگرها به طور پیش‌فرض دسترسی به WebAuthn را در iframe های cross-origin مسدود می‌کنند. سیاست مجوزها ، مکانیسم یکپارچه پلتفرم وب است که به یک سند سطح بالا اجازه می‌دهد تا صریحاً این قابلیت‌های قدرتمند را به منابع شخص ثالث خاص و مورد اعتماد واگذار کند.

توکن‌های ویژگی

WebAuthn از دو توکن مجزا استفاده می‌کند:

  • publickey-credentials-get : مجوز لازم برای جریان‌های ورود با کلید عبور را اعطا می‌کند ( navigator.credentials.get() ).
  • publickey-credentials-create : مجوز لازم برای جریان‌های ثبت رمز عبور ( navigator.credentials.create() ) را اعطا می‌کند.

الزامات مربوط به توانمندسازی

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

Permissions-Policy: publickey-credentials-get=(self "https://embedded-auth.example.com")

سیاست مجوزها: سازگاری publickey-credentials-get:

Browser Support

  • کروم: ۸۸.
  • لبه: ۸۸.
  • فایرفاکس: پشتیبانی نمی‌شود.
  • سافاری: پشتیبانی نمی‌شود.

Source

سیاست مجوزها: سازگاری publickey-credentials-create:

Browser Support

  • کروم: ۸۸.
  • لبه: ۸۸.
  • فایرفاکس: پشتیبانی نمی‌شود.
  • سافاری: پشتیبانی نمی‌شود.

Source

  • ویژگی allow در HTML: در نشانه‌گذاری HTML، عنصر <iframe> باید همچنین اعلام کند که این ویژگی را فعال می‌کند.
<iframe src="https://embedded-auth.example.com?nonce=deadbeef12345678&client=https%3A%2F%2Fembedded-auth.example.com" allow="publickey-credentials-get"></iframe>

سازگاری iframe allow="publickey-credentials-get":

Browser Support

  • کروم: ۸۴.
  • لبه: ۸۴.
  • فایرفاکس: ۱۱۸.
  • سافاری: پشتیبانی نمی‌شود.

سازگاری iframe allow="publickey-credentials-create":

Browser Support

  • کروم: پشتیبانی نمی‌شود.
  • لبه: پشتیبانی نمی‌شود.
  • فایرفاکس: ۱۲۳.
  • سافاری: پشتیبانی نمی‌شود.

کوکی‌های شخص ثالث پارتیشن‌بندی‌شده را فعال کنید

برای اطمینان از یک جریان احراز هویت قابل اعتماد، باید یک جلسه (session) در داخل iframe کراس-اوریجین تعبیه شده ایجاد و نگهداری شود. از آنجایی که مرورگرهای مدرن به محدودیت‌های سختگیرانه کوکی‌های شخص ثالث روی آورده‌اند، مکانیسم‌های استاندارد پایداری اغلب به طور پیش‌فرض مسدود می‌شوند و ممکن است برای دسترسی نیاز به فراخوانی API دسترسی به حافظه (Storage Access API) داشته باشند.

برای کاهش این موانع، کوکی‌های جلسه خود را با ویژگی‌های SameSite: None ، Secure و Partitioned پیکربندی کنید. این مکانیزم یکپارچه پلتفرم، ضمن رعایت کنترل‌های حریم خصوصی در سطح مرورگر، وضعیت پایدار را در iframe تضمین می‌کند.

تنظیم SameSite: None

SameSite: None به طور صریح یک کوکی را برای دسترسی بین سایتی علامت گذاری می‌کند و اجازه می‌دهد تا با درخواست‌های ارسال شده از یک زمینه شخص ثالث (مانند یک iframe) ارسال شود. این ویژگی پیش‌نیازی برای عملکرد کوکی‌ها در سناریوهای بین مبدایی است، اگرچه باید با ویژگی Secure ترکیب شود تا توسط مرورگرهای مدرن پذیرفته شود.

مجموعه Partitioned

ویژگی Partitioned کوکی را در CHIPS (کوکی‌هایی با حالت پارتیشن‌بندی مستقل) قرار می‌دهد و اجازه می‌دهد کوکی برای هر سایت سطح بالا به طور جداگانه ذخیره شود. این امر تضمین می‌کند که کوکی در چارچوب iframe شخص ثالث خاص قابل دسترسی باقی بماند و حالت جلسه پایدار را بدون فعال کردن ردیابی بین سایتی فعال کند. کاربر باید برای هر جاسازی در سایت دیگری دوباره وارد سیستم شود.

با سیاست امنیتی محتوا، از نقطه پایانی محافظت کنید

در حالی که سیاست مجوزها تعیین می‌کند که آیا iframe شما می‌تواند WebAuthn را اجرا کند یا خیر، سیاست امنیت محتوا (CSP) تعیین می‌کند که چه کسی مجاز به میزبانی iframe شما است.

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

استفاده frame-ancestors

دستورالعمل frame-ancestors صفحات والد معتبری را که می‌توانند سایت شما را جاسازی کنند، تعریف می‌کند. با اضافه کردن دامنه‌ها به این دستورالعمل، می‌توانید به دامنه‌هایی که مجاز به جاسازی زیرفریم ورود هستند، اجازه دهید.

Content-Security-Policy: frame-ancestors 'self' https://parent-site.example.com;

سیاست امنیتی محتوا: سازگاری با فریم-اجداد:

Browser Support

  • کروم: ۴۰.
  • لبه: ۱۵.
  • فایرفاکس: ۵۸.
  • سافاری: ۱۰.

Source

تنظیمات X-Frame-Options

هدر قدیمی X-Frame-Options از قابلیت مشابهی پشتیبانی می‌کند، اما فقط از گزینه‌های دودویی ( DENY یا SAMEORIGIN ) پشتیبانی می‌کند. در صورتی که مرورگر از CSP پشتیبانی نمی‌کند، هر دو CSP frame-ancestors و X-Frame-Options: DENY را تنظیم کنید. CSP همیشه در جایی که پشتیبانی می‌شود، اولویت دارد.

X-Frame-Options: DENY

سازگاری با گزینه‌های X-Frame:

Browser Support

  • کروم: ۴.
  • لبه: ۱۲.
  • فایرفاکس: ۴.
  • سافاری: ۴.

Source

اعتماد کنید، اما سمت سرور را تأیید کنید

بررسی‌های سمت کلاینت مرورگر، قصد و مجوزها را ارزیابی می‌کنند، اما سرور داور نهایی اعتماد است. پاسخ را در سرور Relying Party (RP) تأیید کنید تا از معتبر و امضا شده بودن زمینه اطمینان حاصل شود.

بار داده کلاینت

داده‌های کلاینت WebAuthn شامل پارامترهایی است که به‌طور خاص برای کمک به شما در تأیید زمینه‌ی درخواستی که درون یک iframe انجام می‌شود، طراحی شده‌اند:

  • crossOrigin (boolean): نشان می‌دهد که آیا API WebAuthn درون یک iframe کراس-اوریجین فراخوانی شده است یا خیر. اگر معماری شما به iframeها متکی است، سرور شما باید این پرچم را روی true تنظیم کند.
  • topOrigin (رشته): مبداء زمینه مرور سطح بالا (آنچه در نوار آدرس مرورگر قابل مشاهده است). سرور باید این را با لیستی از مبداءهای والد شناخته شده و مجاز تأیید کند.

چک لیست تأیید

برای تأیید پاسخ تأییدکننده روی سرور خود، مراحل زیر را انجام دهید:

  1. داده‌های امضا شده‌ی collectedClientData را از پاسخ احراز هویت‌کننده تجزیه و رمزگشایی کنید.
  2. مطمئن شوید که type با مراسم مطابقت دارد ( webauthn.get یا webauthn.create ).
  3. حضور و امضای کاربر را تأیید کنید.
  4. اگر قرار بود درخواست از یک ساختار iframe ارسال شود:
    • اعمال crossOrigin === true .
    • اطمینان حاصل کنید که topOrigin با فهرست مجاز ریشه‌های والد شما مطابقت داشته باشد.

ایجاد جلسات امن با استفاده از postMessage()

برای ایجاد یک نشست به صورت قابل اعتماد، iframe باید توکن احراز هویت را با استفاده از postMessage() به صفحه والد برگرداند و به والد اجازه دهد وضعیت نشست را در زمینه شخص اول خود مدیریت کند.

گردش کار امن

برای ایجاد یک جلسه امن، این گردش کار را دنبال کنید:

  1. مطمئن شوید که آدرس اینترنتی iframe src حاوی پارامترهای nonce و origin query باشد:
    • از یک مقدار تصادفی برای nonce استفاده کنید. nonce به عنوان یک توکن تأیید امنیتی عمل می‌کند تا اطمینان حاصل شود که توکن احراز هویت دریافت شده از یک iframe به طور قانونی با جلسه خاص آغاز شده توسط صفحه والد مطابقت دارد.
    • از دامنه فریم والد برای origin استفاده کنید. پارامتر origin ، مبدا صفحه والد را مشخص می‌کند و به iframe این امکان را می‌دهد که به طور ایمن زمینه مجاز تعبیه شده در آن را شناسایی کند.
  2. iframe احراز هویت WebAuthn را با سرور خودش تکمیل می‌کند.
  3. سرور iframe یک توکن مانند JWT صادر می‌کند که شامل nonce است و آن را به صفحه والد ارسال می‌کند.

    // Extract nonce and origin from the URL params
    const urlParams = new URLSearchParams(window.location.search);
    const nonce = urlParams.get('nonce');
    const origin = urlParams.get('origin');
    if (!nonce || !origin) {
      alert('Nonce or origin is missing in the URL');
      return;
    }
    
    // Create a JWT
    const response = await post('/createToken', { nonce, origin });
    const token = response.token;
    
    // Post the JWT to the parent frame
    window.parent.postMessage({ token }, origin);
    
  4. صفحه والد به رویداد message گوش می‌دهد، مبدا فرستنده را اعتبارسنجی می‌کند و توکن را تأیید می‌کند.

    window.addEventListener("message", (event) => {
      if (event.origin !== "https://embedded-auth.example.com") return;
      // Verify the received JWT
      const result = await post('/verifyIdToken', {
        token: event.data.token,
        origin: provider.origin,
      });
    });
    
  5. اگر JWT با موفقیت تأیید شود، صفحه والد، نشست را حفظ می‌کند.

فرستنده و گیرنده هر دو مسئولیت‌های امنیتی را به اشتراک می‌گذارند:

  • فرستنده (iframe): هنگام ارسال پیام، همیشه یک مبدا هدف دقیق مشخص کنید (هرگز از "*" استفاده نکنید).
  • گیرنده (والد): همیشه هنگام دریافت پیام‌ها، event.origin را تأیید کنید تا از جعل مبدأ جلوگیری شود.

نتیجه‌گیری

استفاده ایمن از iframe به Permissions Policy برای فعال‌سازی، CSP برای محدودسازی، کوکی‌های پارتیشن‌بندی شده شخص ثالث برای ماندگاری session، تأیید سمت سرور از متن کلاینت و انتقال session با توجه به متن با استفاده از postMessage() بستگی دارد.

برای کسب اطلاعات بیشتر در مورد موضوعات مرتبط، وبلاگ توسعه‌دهندگان کروم گوگل را دنبال کنید و منابع بیشتر را در مستندات هویت توسعه‌دهندگان کروم بررسی کنید.