Menggunakan eval di ekstensi Chrome

Sistem ekstensi Chrome menerapkan Kebijakan Keamanan Konten (CSP) default yang cukup ketat. Pembatasan kebijakannya sangat jelas: skrip harus dipindahkan keluar baris menjadi File JavaScript, pengendali peristiwa inline harus dikonversi untuk menggunakan addEventListener, dan eval() adalah dinonaktifkan. Aplikasi Chrome memiliki kebijakan yang lebih ketat, dan kami cukup puas dengan keamanannya yang disediakan oleh kebijakan ini.

Namun, kami menyadari bahwa berbagai library menggunakan konstruksi seperti eval() dan eval seperti new Function() untuk pengoptimalan performa dan kemudahan berekspresi. Library template sangat rentan terhadap gaya implementasi ini. Meskipun beberapa (seperti Angular.js) mendukung CSP out standar, banyak kerangka kerja populer yang belum diperbarui menjadi mekanisme yang kompatibel dengan ekstensi' Dunia lebih sedikit eval. Menghapus dukungan untuk fungsi tersebut terbukti lebih bermasalah dari yang diharapkan bagi developer.

Dokumen ini memperkenalkan sandboxing sebagai mekanisme yang aman untuk menyertakan library-library ini dalam project Anda tanpa mengorbankan keamanan. Untuk singkatnya, kami akan menggunakan istilah ekstensi secara keseluruhan, tapi konsep ini berlaku sama untuk aplikasi.

Mengapa menggunakan sandbox?

eval berbahaya di dalam ekstensi karena kode yang dijalankan memiliki akses ke semua hal di lingkungan izin akses tinggi ekstensi. Tersedia berbagai API chrome.* andal yang dapat sangat memengaruhi keamanan dan privasi pengguna; pemindahan data secara tidak sah adalah hal yang paling tidak kami khawatirkan. Solusi yang ditawarkan adalah sandbox tempat eval dapat mengeksekusi kode tanpa akses ke data ekstensi atau API bernilai tinggi dari ekstensi. Tidak ada data, tidak ada API, tidak masalah.

Kami melakukannya dengan mencantumkan file HTML tertentu di dalam paket ekstensi sebagai yang di-sandbox. Setiap kali halaman dalam sandbox dimuat, halaman tersebut akan dipindahkan ke asal yang unik, dan akan ditolak akses ke chrome.* API. Jika kita memuat halaman yang di-sandbox ini ke dalam ekstensi melalui iframe, kita bisa meneruskan pesannya, membiarkannya bertindak terhadap pesan itu dengan cara tertentu, dan menunggunya memberikan kembali hasil pengujian tersebut. Mekanisme pesan yang sederhana ini memberikan semua yang kami butuhkan untuk menyertakan aman berbasis eval dalam alur kerja ekstensi kita.

Membuat dan menggunakan sandbox.

Jika Anda ingin langsung mempelajari kode, ambil ekstensi contoh sandboxing dan ikuti nonaktif. Ini adalah contoh API pesan kecil yang berfungsi dan dibangun di atas Handlebar membuat template library, dan ini akan memberi Anda semua yang Anda perlukan untuk memulai. Bagi Anda yang ingin seperti sedikit penjelasan lebih lanjut, mari kita kita bahas contoh itu bersama-sama di sini.

Mencantumkan file dalam manifes

Setiap file yang harus dijalankan di dalam sandbox harus tercantum dalam manifes ekstensi dengan menambahkan elemen sandbox. Ini adalah langkah yang penting, dan mudah dilupakan, jadi periksa kembali apakah file yang telah di-sandbox akan tercantum di manifes. Dalam contoh ini, kami meng-{i>sandbox<i} file dengan cerdas bernama "sandbox.html". Entri manifes akan terlihat seperti ini:

{
  ...,
  "sandbox": {
     "pages": ["sandbox.html"]
  },
  ...
}

Memuat file dalam sandbox

Untuk melakukan sesuatu yang menarik dengan file {i>sandbox<i}, kita perlu mengunggahnya dalam konteks di mana dapat ditangani oleh kode ekstensi. Di sini, sandbox.html telah dimuat ke dalam Halaman Peristiwa ekstensi (eventpage.html) melalui iframe. eventpage.js berisi kode yang mengirim pesan ke sandbox setiap kali tindakan browser diklik dengan mencari iframe di halaman, dan menjalankan metode postMessage di contentWindow. Pesan adalah objek yang berisi dua properti: context dan command. Kita akan segera membahas keduanya.

chrome.browserAction.onClicked.addListener(function() {
 var iframe = document.getElementById('theFrame');
 var message = {
   command: 'render',
   context: {thing: 'world'}
 };
 iframe.contentWindow.postMessage(message, '*');
});
Untuk informasi umum tentang postMessage API, lihat dokumentasi postMessage di MDN . Konten ini cukup lengkap dan layak dibaca. Secara khusus, perlu diperhatikan bahwa data hanya dapat diteruskan bolak-balik jika dapat diserialisasi. Fungsi, misalnya, tidak bersifat umum.

Lakukan hal berbahaya

Saat sandbox.html dimuat, library ini akan memuat library Handlebars, serta membuat dan mengompilasi sebuah inline seperti yang disarankan oleh Handlebars:

<script src="handlebars-1.0.0.beta.6.js"></script>
<script id="hello-world-template" type="text/x-handlebars-template">
  <div class="entry">
    <h1>Hello, !</h1>
  </div>
</script>
<script>
  var templates = [];
  var source = document.getElementById('hello-world-template').innerHTML;
  templates['hello'] = Handlebars.compile(source);
</script>

Ini tidak gagal! Meskipun Handlebars.compile akhirnya menggunakan new Function, semuanya berfungsi seperti yang diharapkan, dan kita mendapatkan template yang dikompilasi di templates['hello'].

Meneruskan hasilnya kembali

Kita akan menyediakan template ini untuk digunakan dengan menyiapkan pemroses pesan yang menerima perintah dari Halaman Peristiwa. Kita akan menggunakan command yang diteruskan untuk menentukan apa yang harus dilakukan (Anda dapat bayangkan melakukan lebih dari sekadar rendering; mungkin membuat {i>template<i}? Mungkin mengelolanya di beberapa ?), dan context akan diteruskan ke template secara langsung untuk rendering. HTML yang dirender akan diteruskan kembali ke Halaman Peristiwa sehingga ekstensi dapat melakukan sesuatu yang bermanfaat di lain waktu:

<script>
  window.addEventListener('message', function(event) {
    var command = event.data.command;
    var name = event.data.name || 'hello';
    switch(command) {
      case 'render':
        event.source.postMessage({
          name: name,
          html: templates[name](event.data.context)
        }, event.origin);
        break;

      // case 'somethingElse':
      //   ...
    }
  });
</script>

Kembali ke Halaman Acara, kita akan menerima pesan ini, dan melakukan sesuatu yang menarik dengan html data yang telah kita teruskan. Dalam hal ini, kita hanya akan menggemakannya melalui Notifikasi Desktop, tetapi HTML ini dapat digunakan dengan aman sebagai bagian dari UI ekstensi. Menyisipkannya melalui innerHTML tidak menimbulkan risiko keamanan yang signifikan, bahkan penyusupan sepenuhnya terhadap proses sandbox kode melalui beberapa serangan pintar tidak akan dapat menginjeksikan skrip berbahaya atau konten {i>plugin<i} ke konteks ekstensi dengan izin tinggi.

Mekanisme ini membuat pembuatan template menjadi mudah, tetapi tentu saja tidak terbatas pada pembuatan template. Apa saja kode yang tidak berfungsi secara langsung dalam Kebijakan Keamanan Konten yang ketat dapat di-sandbox; inci Namun, sering kali ada baiknya untuk melakukan sandbox komponen ekstensi Anda yang akan berjalan dengan benar dalam urutan untuk membatasi setiap bagian dari program Anda ke rangkaian hak istimewa terkecil yang diperlukan agar dapat berjalan dengan baik. Presentasi Writing Secure Web Apps and Chrome Extensions dari Google I/O 2012 memberikan beberapa contoh yang baik dari penerapan teknik ini, dan bernilai 56 menit dari baik.