Async Clipboard API'deki temizlenmemiş HTML

Chrome 120'den itibaren, Eş Zamansız Pano'ya yeni bir unsanitized seçeneği eklendi API'ye gidin. Bu seçenek, bazı durumlarda pano içeriğini, kopyalandığı zamanki haliyle yapıştırır. Yani, tarayıcılar tarafından yaygın olarak kullanılan herhangi bir ara temizleme adımı olmadan iyi bir nedendir; başvurun. Bu kılavuzu nasıl kullanacağınızı bu kılavuzdan öğrenebilirsiniz.

Proje yöneticileri Async Clipboard API'si Çoğu durumda geliştiricilerin, bilgilerin doğruluğu konusunda panodaki içeriğe sahiptir ve sayfaya yazdıklarını panodaki (kopya), web sitesindeki verileri okuduklarında görecekleriyle aynıdır panoya yapıştırın (yapıştır).

Bu kesinlikle metin için geçerlidir. Aşağıdaki kodu Geliştirici Araçları'na yapıştırmayı deneyin sonra hemen sayfaya yeniden odaklayın. (setTimeout() gereklidir Böylece, sayfaya odaklanmak için yeterli zamanınız olur. Bu, Eşzamansız Clipboard API'si.) Gördüğünüz gibi giriş, çıkışla tamamen aynıdır.

setTimeout(async () => {
  const input = 'Hello';
  await navigator.clipboard.writeText(input);
  const output = await navigator.clipboard.readText();
  console.log(input, output, input === output);
  // Logs "Hello Hello true".
}, 3000);

Resimlerle bu durum biraz farklıdır. Trafiğin tıkanmasının önlenmesi için sıkıştırma bombası saldırıları, tarayıcılar PNG gibi resimleri yeniden kodlayın, ancak giriş ve çıkış resimleri görsel olarak aynı, piksel başına piksel.

setTimeout(async () => {
  const dataURL =
    'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=';
  const input = await fetch(dataURL).then((response) => response.blob());
  await navigator.clipboard.write([
    new ClipboardItem({
      [input.type]: input,
    }),
  ]);
  const [clipboardItem] = await navigator.clipboard.read();
  const output = await clipboardItem.getType(input.type);
  console.log(input.size, output.size, input.type === output.type);
  // Logs "68 161 true".
}, 3000);

Peki, HTML metinlerine ne olur? Tahmin edebileceğiniz gibi, HTML ile farklı olduğunu anlayabilirsiniz. Bu durumda tarayıcı, hatalı olabilecek içeriği önlemek için HTML kodunu şeylerin olmasını engelleyebilirsiniz (örneğin, HTML'den <script> etiketlerini çıkarabilirsiniz) kodunu (ve <meta>, <head>, <style> gibi diğerleri) kullanabilir ve CSS'yi satır içine alabilirsiniz. Aşağıdaki örneği değerlendirip Geliştirici Araçları Konsolu'nda deneyin. Bu kurstan sonra çıkışın girişten oldukça farklı olduğuna dikkat edin.

setTimeout(async () => {
  const input = `<html>  
  <head>  
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
    <meta name="ProgId" content="Excel.Sheet" />  
    <meta name="Generator" content="Microsoft Excel 15" />  
    <style>  
      body {  
        font-family: HK Grotesk;  
        background-color: var(--color-bg);  
      }  
    </style>  
  </head>  
  <body>  
    <div>hello</div>  
  </body>  
</html>`;
  const inputBlob = new Blob([input], { type: 'text/html' });
  await navigator.clipboard.write([
    new ClipboardItem({
      'text/html': inputBlob,
    }),
  ]);
  const [clipboardItem] = await navigator.clipboard.read();
  const outputBlob = await clipboardItem.getType('text/html');
  const output = await outputBlob.text();
  console.log(input, output);
}, 3000);

HTML temizleme işlemi genellikle iyi bir şeydir. Kendinizi teşhir etmek istemezsiniz, gerekli düzeltmeler yapılmamış HTML'ye izin vererek güvenlik sorunlarını gidermeye çalışır. Orada geliştiricinin bu senaryolarda tam olarak ne yaptığını bilmesi ve Bu noktada giriş ve çıkış HTML’sinin bütünlüğünün kritik öneme sahip olması sağlanır. Bu durumda iki seçeneğiniz vardır:

  1. Hem kopyalama hem de yapıştırma sonunu kontrol ediyorsanız (örneğin, aynı şekilde uygulamanızın içinde yapıştırmak için Async Clipboard API için web özel biçimleri. Burada okumayı bırakın ve bağlantılı makaleyi kontrol edin.
  2. Uygulamanızda yalnızca yapıştırma ucunu kontrol edip kopyalama sonunu kontrol etmiyorsanız Bunun nedeni kopyalama işleminin web özel biçimleri için unsanitized seçeneğini kullanmanız gerekir. bu makalenin devamında bulabilirsiniz.

Temizlik işlemi, script etiketlerini kaldırma, stilleri satır içine alma ve emin olmak için HTML’nin iyi bir şekilde biçimlendirildiğinden emin olun. Bu liste tam kapsamlı değildir ve daha fazlası daha sonra adım adım eklenebilir.

Düzeltilmemiş HTML'yi kopyalayıp yapıştırın

Eş zamansız Clipboard API'sini kullanarak HTML'yi panoya write() (kopyaladığınızda) tarayıcı, bir DOM ayrıştırıcısı ile çalıştırarak iyi biçimlendirildiğinden emin olmasını sağlar ve sonuç olarak ortaya çıkan HTML dizesi serileştiriliyor, ancak bu adım için daha fazla bilgi edinin. Herhangi bir işlem yapmanız gerekmiyor. read() HTML belgesinin başka bir uygulama tarafından panoya kopyalandığında, web uygulamanız da tam kaliteye sahip içerik ve kendi kodunuzda temizleme işlemi gerçekleştirme gereksinimi, read() yöntemine bir özellik nesnesi aktarabilirsiniz unsanitized ve ['text/html'] değeri. Tek başına şu şekilde görünür: navigator.clipboard.read({ unsanitized: ['text/html'] }) Aşağıdaki kod örneği aşağıda gösterilenle hemen hemen aynı, ancak bu sefer unsanitized seçeneğini belirleyin. Geliştirici Araçları Konsolu'nda denediğinizde, girdiğiniz girişin ve aynı olur.

setTimeout(async () => {
  const input = `<html>  
  <head>  
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
    <meta name="ProgId" content="Excel.Sheet" />  
    <meta name="Generator" content="Microsoft Excel 15" />  
    <style>  
      body {  
        font-family: HK Grotesk;  
        background-color: var(--color-bg);  
      }  
    </style>  
  </head>  
  <body>  
    <div>hello</div>  
  </body>  
</html>`;
  const inputBlob = new Blob([input], { type: 'text/html' });
  await navigator.clipboard.write([
    new ClipboardItem({
      'text/html': inputBlob,
    }),
  ]);
  const [clipboardItem] = await navigator.clipboard.read({
    unsanitized: ['text/html'],
  });
  const outputBlob = await clipboardItem.getType('text/html');
  const output = await outputBlob.text();
  console.log(input, output);
}, 3000);

Tarayıcı desteği ve özellik algılama

Özelliğin desteklenip desteklenmediğini kontrol etmenin doğrudan bir yolu yoktur. Bu nedenle, davranışı gözlemlemeye dayalıdır. Bu nedenle, aşağıdaki örnek değer, <style> etiketinin hayatta kalıp kalmadığına dayanır. destekleniyor olduğunu veya satır içinde olduğunu gösterir; bu da desteklenmediği anlamına gelir. Lütfen çalışması için, sayfanın panoyu almış olması gerekir izni gerekir.

const supportsUnsanitized = async () => {
  const input = `<style>p{color:red}</style><p>a`;
  const inputBlob = new Blob([input], { type: 'text/html' });
  await navigator.clipboard.write([
    new ClipboardItem({
      'text/html': inputBlob,
    }),
  ]);
  const [clipboardItem] = await navigator.clipboard.read({
    unsanitized: ['text/html],
  });
  const outputBlob = await clipboardItem.getType('text/html');
  const output = await outputBlob.text();
  return /<style>/.test(output);
};

Demo

unsanitized seçeneğinin işleyiş şeklini görmek için şuraya bakın: Glitch'te demo yapın ve kaynak kodu.

Sonuçlar

Girişte belirtildiği gibi çoğu geliştiricinin pano temizleme ve varsayılan temizleme seçenekleriyle çalışabilir yaptığı gibidir. Geliştiricilerin bu konuya önem vermesi gereken nadir durumlarda, unsanitized seçeneği mevcut.

Teşekkür

Bu makale Anupam Snigdha ve Rıza Ahmet. API belirtilmiş ve tarafından geliştirilmiştir.