Kontrollü Çerçeve

Demián Renzulli
Demián Renzulli
Simon Hangl
Simon Hangl

<iframe> öğesi genellikle harici kaynakları bir göz atma bağlamına yerleştirmek için kullanılır. Iframe'ler, farklı kaynaklardan yerleştirilmiş içeriği ana makine sayfasından ve ana makine sayfasını da farklı kaynaklardan yerleştirilmiş içerikten izole ederek web'in güvenlik politikalarını zorunlu kılar. Bu yaklaşım, kaynaklar arasında güvenli bir sınır sağlayarak güvenliği artırsa da bazı kullanım alanlarını sınırlar. Örneğin, kullanıcıların farklı kaynaklardaki içerikleri dinamik olarak yüklemesi ve yönetmesi gerekebilir. Örneğin, bir öğretmen, sınıf ekranında bir web sayfasını görüntülemek için gezinme etkinliğini tetikleyebilir. Ancak birçok web sitesi, X-Frame-Options ve İçerik Güvenliği Politikası (İGP) gibi güvenlik başlıklarını kullanarak iFrame'lere yerleştirmeyi açıkça engeller. Ayrıca, iframe kısıtlamaları, yerleştirilen sayfaların yerleştirilmiş içeriğin gezinmesini veya davranışını doğrudan yönetmesini engeller.

Controlled Frame API, kısıtlayıcı yerleştirme politikaları uygulasa bile herhangi bir web içeriğinin yüklenmesine izin vererek bu sınırlamayı giderir. Bu API, hem kullanıcıları hem de geliştiricileri olası risklerden korumak için ek güvenlik önlemleri içeren Yalıtılmış Web Uygulamaları (IWA'lar)'da kullanılabilir.

Controlled Frame'i uygulama

Kontrollü çerçeve kullanmadan önce işlevsel bir IWA ayarlamanız gerekir. Ardından, Kontrollü Çerçeveler'i sayfalarınıza entegre edebilirsiniz.

İzin politikası ekleme

Controlled Frame'leri kullanmak için IWA manifestinize permissions_policy alanını "controlled-frame" değeriyle ekleyerek ilgili izni etkinleştirin. Ayrıca, cross-origin-isolated anahtarını da ekleyin. Bu anahtar, Controlled Frame'e özel değildir ancak tüm IWA'lar için gereklidir ve belgenin, kaynaklar arası yalıtım gerektiren API'lere erişip erişemeyeceğini belirler.

{
   ...
  "permissions_policy": {
     ...
     "controlled-frame": ["self"],
     "cross-origin-isolated": ["self"]
     ...
  }
   ...
}

Yalıtılmış web uygulaması (IWA) manifestindeki controlled-frame anahtarı, izin politikası izin verilenler listesini tanımlar ve hangi kaynakların Controlled Frame'leri kullanabileceğini belirtir. Manifest, Permissions Policy'nin tam söz dizimini destekler. Bu sayede * gibi değerlere, belirli kaynaklara veya self ve src gibi anahtar kelimelere izin verilir. Ancak IWA'ya özgü API'lerin diğer kaynaklara devredilemeyeceğini unutmamak önemlidir. İzin verilenler listesi joker karakter veya harici kaynaklar içerse bile bu izinler controlled-frame gibi IWA özelliklerinde geçerli olmaz. Standart web uygulamalarının aksine, IWA'lar politika kontrollü tüm özellikleri varsayılan olarak "yok" şeklinde ayarlar ve açık beyanlar gerektirir. IWA'ya özgü özellikler için bu, yalnızca self (IWA'nın kendi kaynağı) veya src (yerleştirilmiş bir çerçevenin kaynağı) gibi değerlerin işlevsel olarak etkili olduğu anlamına gelir.

Kontrollü çerçeve öğesi ekleme

Üçüncü taraf içeriğini IWA'nıza yerleştirmek için HTML'nize bir <controlledframe> öğesi ekleyin.

<controlledframe id="controlledframe_1" src="https://example.com">
</controlledframe>

İsteğe bağlı partition özelliği, yerleştirilmiş içerik için depolama alanı bölümlemeyi yapılandırır. Böylece, oturumlar arasında verilerin kalıcı olması için çerezler ve yerel depolama alanı gibi verileri izole edebilirsiniz.

Örnek: Bellek içi depolama bölümü

"session1" adlı bellek içi depolama bölümünü kullanarak kontrollü bir çerçeve oluşturun. Bu bölümde depolanan veriler (ör. çerezler ve localStorage), çerçeve yok edildiğinde veya uygulama oturumu sona erdiğinde temizlenir.

<controlledframe id="controlledframe_1" src="https://example.com">
</controlledframe>

Örnek: Kalıcı depolama bölümü

"user_data" adlı kalıcı depolama bölümünü kullanarak kontrollü bir çerçeve oluşturun. "persist:" öneki, bu bölümde depolanan verilerin diske kaydedilmesini ve uygulama oturumlarında kullanılabilmesini sağlar.

<controlledframe id="frame_2" src="..." partition="persist:user_data">
</controlledframe>

Öğe referansı alma

<controlledframe> öğesine referans alın. Böylece, bu öğeyle herhangi bir standart HTML öğesi gibi etkileşimde bulunabilirsiniz:

const controlledframe = document.getElementById('controlledframe_1');

Sık karşılaşılan senaryolar ve kullanım alanları

Genel bir kural olarak, gereksiz karmaşıklığı önlerken ihtiyaçlarınızı karşılayacak en iyi teknolojiyi seçin. Son yıllarda progresif web uygulamaları (PWA), yerel uygulamalarla arasındaki farkı kapatarak güçlü web deneyimleri sunmaya başladı. Bir web uygulamasının üçüncü taraf içeriği yerleştirmesi gerekiyorsa öncelikle normal <iframe> yaklaşımını kullanmanız önerilir. Gereksinimler iFrame'lerin özelliklerini aşıyorsa IWA'lardaki Controlled Frame'ler en iyi alternatif olabilir. Yaygın kullanım alanları aşağıdaki bölümlerde açıklanmıştır.

Üçüncü taraf web içeriğini yerleştirme

Birçok uygulamanın, kullanıcı arayüzünde üçüncü taraf içeriklerini yükleyip gösterme özelliği olması gerekir. Ancak birden fazla web uygulaması sahibi söz konusu olduğunda (yerleştirilmiş uygulamalarda yaygın bir senaryo) tutarlı uçtan uca politikalar oluşturmak zorlaşır. Örneğin, güvenlik ayarları, işletmelerin bunu yapması için meşru bir ihtiyaç olsa bile geleneksel bir <iframe> öğesinin belirli içerik türlerini yerleştirmesini engelleyebilir. <iframe> öğelerinin aksine, kontrollü çerçeveler bu kısıtlamaları atlamak için tasarlanmıştır. Bu sayede, standart yerleştirmeyi açıkça yasaklasa bile uygulamaların içerik yüklemesine ve göstermesine olanak tanır.

Kullanım alanları

  • Classroom sunumları: Bir öğretmen, normalde iFrame yerleştirmeyi engelleyen eğitim kaynakları arasında geçiş yapmak için sınıfta dokunmatik ekran kullanıyor.
  • Perakende veya alışveriş merkezlerinde dijital tabela: Bir alışveriş merkezi kioskunda farklı mağazaların web siteleri gösterilir. Kontrollü çerçeveler, yerleştirmeyi kısıtlasalar bile bu sayfaların doğru şekilde yüklenmesini sağlar.

Kod örnekleri

Aşağıdaki Controlled Frame API'leri, yerleştirilmiş içeriği yönetmek için yararlıdır.

Gezinme: Controlled Frame'ler, yerleştirilmiş içeriğin gezinmesini ve gezinme geçmişini programatik olarak yönetmek ve kontrol etmek için birden fazla yöntem sunar.

src özelliği, çerçevede gösterilen içeriğin URL'sini alır veya ayarlar. Bu özellik, HTML özelliğiyle aynı şekilde çalışır.

controlledframe.src = "https://example.com";

back() yöntemi, çerçeve geçmişinde bir adım geri gider. Döndürülen söz, gezinmenin başarılı olup olmadığını belirten bir boole değeriyle sonuçlanır.

document.getElementById('backBtn').addEventListener('click', () => {
controlledframe.back().then((success) => {
console.log(`Back navigation ${success ? 'succeeded' : 'failed'}`); }).catch((error) => {
   console.error('Error during back navigation:', error);
   });
});

forward() yöntemi, çerçeve geçmişinde bir adım ileri gider. Döndürülen söz, gezinmenin başarılı olup olmadığını belirten bir boole değeriyle sonuçlanır.

document.getElementById('forwardBtn').addEventListener('click', () => {
controlledframe.forward().then((success) => {
   console.log(`Forward navigation ${success ? 'succeeded' : 'failed'}`);
}).catch((error) => {
    console.error('Error during forward navigation:', error);
  });
});

reload() yöntemi, çerçevedeki geçerli sayfayı yeniden yükler.

document.getElementById('reloadBtn').addEventListener('click', () => {
   controlledframe.reload();
});

Ayrıca, kontrollü çerçeveler, gezinme isteklerinin tam yaşam döngüsünü (başlatma ve yönlendirmelerden içerik yükleme, tamamlama veya iptale kadar) izlemenize olanak tanıyan etkinlikler sağlar.

  • loadstart: Çerçevede bir gezinme başladığında tetiklenir.
  • loadcommit: Gezinme isteği işlendiğinde ve ana doküman içeriği yüklenmeye başladığında tetiklenir.
  • contentload: Ana belge ve temel kaynakları yüklendiğinde tetiklenir (DOMContentLoaded'a benzer).
  • loadstop: Sayfayla ilgili tüm kaynaklar (alt çerçeveler, resimler dahil) yüklendiğinde tetiklenir.
  • loadabort: Bir gezinme işlemi iptal edilirse (örneğin, kullanıcı işlemiyle veya başka bir gezinme işlemi başlatılarak) tetiklenir.
  • loadredirect: Gezinme sırasında sunucu tarafı yönlendirme gerçekleştiğinde tetiklenir.
controlledframe.addEventListener('loadstart', (event) => {
   console.log('Navigation started:', event.url);
   // Example: Show loading indicator
 });
controlledframe.addEventListener('loadcommit', (event) => {
   console.log('Navigation committed:', event.url);
 });
controlledframe.addEventListener('contentload', (event) => {
   console.log('Content loaded for:', controlledframe.src);
   // Example: Hide loading indicator, maybe run initial script
 });
controlledframe.addEventListener('loadstop', (event) => {
   console.log('All resources loaded for:', controlledframe.src);
 });
controlledframe.addEventListener('loadabort', (event) => {
   console.warn(`Navigation aborted: ${event.url}, Reason: ${event.detail.reason}`);
 });
controlledframe.addEventListener('loadredirect', (event) => {
   console.log(`Redirect detected: ${event.oldUrl} -> ${event.newUrl}`);
});

Ayrıca, kontrollü çerçeveye yüklenen içerik tarafından başlatılan belirli etkileşimleri veya istekleri (ör. iletişim kutularını açma, izin isteme ya da yeni pencereler açma girişimleri) izleyebilir ve potansiyel olarak engelleyebilirsiniz.

  • dialog: Yerleştirilmiş içerik bir iletişim kutusu (uyarı, onay, istem) açmaya çalıştığında tetiklenir. Ayrıntıları alır ve yanıt verebilirsiniz.
  • consolemessage: Bir ileti çerçeve içinde konsola kaydedildiğinde tetiklenir.
  • permissionrequest: Yerleştirilmiş içerik izin istediğinde (ör. coğrafi konum ve bildirimler) tetiklenir. Ayrıntıları alır ve isteği kabul edebilir veya reddedebilirsiniz.
  • newwindow: Yerleştirilmiş içerik yeni bir pencere veya sekme açmaya çalıştığında (ör. window.open ile veya target="_blank" içeren bir bağlantıyla) tetiklenir. Ayrıntıları alıp işlemi gerçekleştirebilir veya engelleyebilirsiniz.
controlledframe.addEventListener('dialog', (event) => {
   console.log(Dialog opened: Type=${event.messageType}, Message=${event.messageText});
   // You will need to respond, e.g., event.dialog.ok() or .cancel()
 });

controlledframe.addEventListener('consolemessage', (event) => {
   console.log(Frame Console [${event.level}]: ${event.message});
 });

controlledframe.addEventListener('permissionrequest', (event) => {
   console.log(Permission requested: Type=${event.permission});
   // You must respond, e.g., event.request.allow() or .deny()
   console.warn('Permission request needs handling - Denying by default');
   if (event.request && event.request.deny) {
     event.request.deny();
   }
});

controlledframe.addEventListener('newwindow', (event) => {
   console.log(New window requested: URL=${event.targetUrl}, Name=${event.name});
   // Decide how to handle this, e.g., open in a new controlled frame and call event.window.attach(), ignore, or block
   console.warn('New window request needs handling - Blocking by default');
 });

Ayrıca, kontrollü çerçevenin kendi oluşturma durumuyla ilgili değişiklikler (ör. boyutlarında veya yakınlaştırma düzeyinde yapılan değişiklikler) hakkında sizi bilgilendiren durum değişikliği etkinlikleri de vardır.

  • sizechanged: Çerçevenin içerik boyutları değiştiğinde tetiklenir.
  • zoomchange: Çerçevenin içeriğinin yakınlaştırma düzeyi değiştiğinde tetiklenir.
controlledframe.addEventListener('sizechanged', (event) => {
  console.log(Frame size changed: Width=${event.width}, Height=${event.height});
});

controlledframe.addEventListener('zoomchange', (event) => {
  console.log(Frame zoom changed: Factor=${event.newZoomFactor});
});

Depolama yöntemleri: Controlled Frames, bir çerçevenin bölümünde depolanan verileri yönetmek için API'ler sunar.

Depolanan tüm verileri kaldırmak için clearData()'ı kullanın. Bu, özellikle bir kullanıcı oturumundan sonra çerçeveyi sıfırlamak veya temiz bir durum sağlamak için kullanışlıdır. Yöntem, işlem tamamlandığında çözümlenen bir Promise döndürür. İsteğe bağlı yapılandırma seçenekleri de sağlanabilir:

  • types: Temizlenecek veri türlerini belirten bir dizeler dizisi (örneğin, ['cookies', 'localStorage', 'indexedDB']). Atlanırsa genellikle geçerli tüm veri türleri temizlenir.
  • options: Yalnızca bu tarihten sonra oluşturulan verileri temizlemek için bir zaman aralığı belirtme (epoch'tan itibaren milisaniye cinsinden zaman damgası) gibi temizleme sürecini kontrol edin.

Örnek: Kontrollü çerçeveyle ilişkili tüm depolama alanını temizleme

function clearAllPartitionData() {
   console.log('Clearing all data for partition:', controlledframe.partition);
   controlledframe.clearData()
     .then(() => {
       console.log('Partition data cleared successfully.');
     })
     .catch((error) => {
       console.error('Error clearing partition data:', error);
     });
}

Örnek: Yalnızca son bir saat içinde oluşturulan çerezleri ve localStorage'ı temizleme

function clearRecentCookiesAndStorage() {
   const oneHourAgo = Date.now() - (60 * 60 * 1000);
   const dataTypesArray = ['cookies', 'localStorage'];
   const dataTypesToClearObject = {};
   for (const type of dataTypesArray) {
      dataTypesToClearObject[type] = true;
   }
   const clearOptions = { since: oneHourAgo };
   console.log(`Clearing ${dataTypesArray.join(', ')} since ${new    Date(oneHourAgo).toISOString()}`); controlledframe.clearData(clearOptions, dataTypesToClearObject) .then(() => {
   console.log('Specified partition data cleared successfully.');
}).catch((error) => {
   console.error('Error clearing specified partition data:', error);
});
}

Üçüncü taraf uygulamalarını genişletme veya değiştirme

Controlled Frame'ler, basit yerleştirmenin ötesinde, yerleştirme IWA'sının yerleştirilmiş üçüncü taraf web içeriği üzerinde kontrol sahibi olmasını sağlayan mekanizmalar sunar. Güvenli ve yalıtılmış bir ortamda yerleştirilmiş içerikteki komut dosyalarını çalıştırabilir, ağ isteklerini engelleyebilir ve varsayılan bağlam menülerini geçersiz kılabilirsiniz.

Kullanım alanları

  • Üçüncü taraf sitelerde markalamayı zorunlu kılma: Birleşik bir görsel tema uygulamak için yerleştirilmiş web sitelerine özel CSS ve JavaScript yerleştirin.
  • Gezinme ve bağlantı davranışını kısıtlama: Komut dosyası yerleştirme ile belirli <a> etiket davranışlarını engelleme veya devre dışı bırakma.
  • Çökme veya işlem yapılmaması durumunda kurtarmayı otomatikleştirme: Yerleştirilmiş içeriği hata durumları (ör. boş ekran, komut dosyası hataları) açısından izleyin ve zaman aşımından sonra oturumu programatik olarak yeniden yükleyin veya sıfırlayın.

Kod örnekleri

Komut dosyası yerleştirme: JavaScript'i kontrollü çerçeveye yerleştirmek için executeScript()'ı kullanın. Bu sayede davranışı özelleştirebilir, yer paylaşımları ekleyebilir veya yerleştirilmiş üçüncü taraf sayfalarından veri ayıklayabilirsiniz. Dize olarak satır içi kod sağlayabilir veya bir ya da daha fazla komut dosyasına (IWA paketi içindeki göreli yolları kullanarak) referans verebilirsiniz. Yöntem, komut dosyasının yürütülmesinin sonucuyla (genellikle son ifadenin değeri) sonuçlanan bir söz döndürür.

document.getElementById('scriptBtn').addEventListener('click', () => {
   controlledframe.executeScript({
      code: `document.body.style.backgroundColor = 'lightblue';
             document.querySelectorAll('a').forEach(link =>    link.style.pointerEvents = 'none');
             document.title; // Return a value
            `,
      // You can also inject files:
      // files: ['./injected_script.js'],
}) .then((result) => {
   // The result of the last statement in the script is usually returned.
   console.log('Script execution successful. Result (e.g., page title):', result); }).catch((error) => {
   console.error('Script execution failed:', error);
   });
});

Stil yerleştirme: Kontrollü bir çerçeveye yüklenen sayfalara özel stiller uygulamak için insertCSS() öğesini kullanın.

document.getElementById('cssBtn').addEventListener('click', () => {
  controlledframe.insertCSS({
    code: `body { font-family: monospace; }`
    // You can also inject files:
    // files: ['./injected_styles.css']
  })
  .then(() => {
    console.log('CSS injection successful.');
  })
  .catch((error) => {
    console.error('CSS injection failed:', error);
  });
});

Ağ İsteği Yakalama: WebRequest API'yi kullanarak yerleştirilmiş sayfadan gelen ağ isteklerini gözlemleyin ve potansiyel olarak değiştirin. Örneğin, istekleri engelleyin, başlıkları değiştirin veya kullanımı kaydedin.

// Get the request object
const webRequest = controlledframe.request;

// Create an interceptor for a specific URL pattern
const interceptor = webRequest.createWebRequestInterceptor({
  urlPatterns: ["*://evil.com/*"],
  blocking: true,
  includeHeaders: "all"
});

// Add a listener to block the request
interceptor.addEventListener("beforerequest", (event) => {
  console.log('Blocking request to:', event.url);
  event.preventDefault();
});

// Add a listener to modify request headers
interceptor.addEventListener("beforesendheaders", (event) => {
  console.log('Modifying headers for:', event.url);
  const newHeaders = new Headers(event.headers);
  newHeaders.append('X-Custom-Header', 'MyValue');
  event.setRequestHeaders(newHeaders);
});

Özel Bağlam Menüleri Ekleme: Yerleştirilmiş çerçeveye özel sağ tıklama menüleri eklemek, bunları kaldırmak ve yönetmek için contextMenus API'sini kullanın. Bu örnekte, kontrollü bir çerçeveye özel bir "Seçimi kopyala" menüsünün nasıl ekleneceği gösterilmektedir. Metin seçildiğinde ve kullanıcı sağ tıkladığında menü görünür. Bu düğme tıklandığında seçili metin panoya kopyalanır. Böylece, yerleştirilmiş içeriklerde basit ve kullanıcı dostu etkileşimler sağlanır.

const menuItemProperties = {
  id: "copy-selection",
  title: "Copy selection",
  contexts: ["selection"],
  documentURLPatterns: [new URLPattern({ hostname: '*.example.com'})]
};

// Create the context menu item using a promise
try {
  await controlledframe.contextMenus.create(menuItemProperties);
  console.log(`Context menu item "${menuItemProperties.id}" created successfully.`);
} catch (error) {
  console.error(`Failed to create context menu item:`, error);
}

// Add a standard event listener for the 'click' event
controlledframe.contextMenus.addEventListener('click', (event) => {
    if (event.menuItemId === "copy-selection" && event.selectionText) {
        navigator.clipboard.writeText(event.selectionText)
          .then(() => console.log("Text copied to clipboard."))
          .catch(err => console.error("Failed to copy text:", err));
    }
});

Demo

Controlled Frame yöntemlerine genel bir bakış için Controlled Frame demosunu inceleyin.

Controlled Frame demosunu

Alternatif olarak, IWA Kitchen Sink'te, her biri Controlled Frames ve Direct Sockets gibi farklı bir IWA API'sini gösteren birden fazla sekmeye sahip bir uygulama bulunur.

IWA Kitchen Sink

Sonuç

Controlled Frame'ler, yalıtılmış web uygulamalarında (IWA) üçüncü taraf web içeriklerini yerleştirmenin, genişletmenin ve bu içeriklerle etkileşim kurmanın güçlü ve güvenli bir yolunu sunar. iframe'lerin sınırlamalarını aşarak yerleştirilmiş içerikte komut dosyalarını yürütme, ağ isteklerini yakalama ve özel bağlam menüleri uygulama gibi yeni özellikler sunar. Tüm bunları sıkı izolasyon sınırlarını koruyarak yapar. Ancak bu API'ler yerleştirilmiş içerik üzerinde derin kontrol sağladığından ek güvenlik kısıtlamalarıyla birlikte gelir ve yalnızca hem kullanıcılar hem de geliştiriciler için daha güçlü garantiler sağlamak üzere tasarlanmış IWA'larda kullanılabilir. Çoğu kullanım alanında geliştiriciler, birçok senaryoda daha basit ve yeterli olan standart <iframe> öğelerini kullanmayı öncelikle düşünmelidir. iFrame tabanlı çözümler yerleştirme kısıtlamaları nedeniyle engellendiğinde veya gerekli kontrol ve etkileşim özelliklerine sahip olmadığında Controlled Frames değerlendirilmelidir. Kontrollü çerçeveler; kiosk deneyimleri oluştururken, üçüncü taraf araçları entegre ederken veya modüler eklenti sistemleri tasarlarken yapılandırılmış, izin verilmiş ve güvenli bir ortamda ayrıntılı kontrol sağlar. Bu nedenle, yeni nesil gelişmiş web uygulamalarında kritik bir araçtır.

Diğer Kaynaklar