Belajar WebAssembly - Keamanan & Sandboxing
Episode 16 of 23

Belajar WebAssembly - Keamanan & Sandboxing

Memahami model keamanan WebAssembly: isolasi memory per-instance, capability-based WASI tanpa raw syscall, Content Security Policy, plus best practice validasi imports, interop tanpa unsafe, dan pengamanan supply-chain dengan cargo audit

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 15 kalian mengoptimasi ukuran dan performa — pada episode ini kita membahas apa yang membuat WebAssembly unik di antara semua teknologi runtime: model keamanannya. Jika kalian membaca episode 1-15 dengan teliti, kalian sudah melihat benang merahnya — sandbox, linear memory, capability — dan kini saatnya merangkainya menjadi gambaran keamanan yang utuh.

Mengapa topik ini penting? Karena Wasm digunakan untuk menjalankan kode yang tidak dipercaya: plugin dari vendor pihak ketiga, fungsi user, atau modul yang diunduh dari CDN. Keamanan bukan fitur tambahan — ia adalah alasan mengapa Wasm bisa dipercaya menjalankan kode asing di browser, edge, dan server.

Isolasi Memory per-Instance

Model keamanan inti Wasm ada di memory linear: setiap instance memiliki memory sendiri yang tidak bisa diakses instance lain. Tidak ada pointer global, tidak ada shared state — kecuali yang di-export secara eksplisit (dan diwasm, SharedArrayBuffer punya aturan ketat sendiri).

Konsekuensi keamanannya:

  • Trap, bukan crash — akses di luar memory menghasilkan trap yang ditangkap host, bukan segfault yang membunuh proses.
  • Tanpa arbitrary code execution — verifikasi statis memastikan hanya instruksi valid yang berjalan.
  • Surface kecil — semua yang bisa dilakukan modul ditentukan oleh imports yang disediakan host.
100%

Dua instance dari modul yang sama (bahkan modul yang berbahaya) tidak bisa saling menyentuh memory — fondasi multi-tenant yang aman.

Capability-Based WASI: Tanpa Raw Syscall

Inilah perbedaan paling fundamental dengan container. Container memakai kernel syscall — mekanisme yang sama dengan host, hanya dibatasi namespace. WASI sama sekali tidak memberi raw syscall; ia hanya menyediakan fungsi abstrak yang mengimplementasikan akses sesuai izin.

Beri akses minimal di Wasmtime
wasmtime run --dir ./data --env TOKEN=x app.wasm
  • --dir ./data — modul hanya bisa mengakses subtree ./data, bukan seluruh filesystem.
  • --env TOKEN=x — hanya environment variable ini yang terlihat.
  • Tanpa flags, modul tidak punya akses apa pun — deny by default.

Jika modul berbahaya mencoba membuka /etc/passwd, ia tidak menemukan mekanisme untuk melakukannya sama sekali — bukan sekadar ditolak izinnya.

Tip

Anggap WASI seperti "lemari terkunci dengan kunci yang diberikan satu per satu": bukan "ruangan besar yang dibatasi pagar" (container). Prinsip ini memudahkan audit: daftar capability sebuah modul bisa dibaca langsung dari perintah runtime yang menjalankannya.

Content Security Policy (CSP)

Di browser, modul Wasm dimuat seperti aset lain — dan harus dikendalikan CSP:

Content-Security-Policy
Content-Security-Policy: default-src 'none';
  script-src 'self';
  wasm-unsafe-eval;
  worker-src 'self' blob:;

Poin penting:

  • wasm-unsafe-eval — mengizinkan eksekusi WebAssembly tanpa 'unsafe-eval' penuh (yang melemahkan keamanan script).
  • worker-src blob: — diperlukan jika memuat modul lewat Web Worker (episode 21).
  • Jangan mencampur 'unsafe-inline' tanpa alasan kuat.

Validasi Imports: Jangan Percaya Modul

Modul Wasm hanya bisa melakukan apa yang imports-nya izinkan. Jadi, validasi imports adalah gerbang keamanan:

JSValidasi dan batasi imports
function safeImports(modul) {
  const izinkan = new Set(["env.log", "env.memory"])
 
  const imports = WebAssembly.Module.imports(modul)
  for (const imp of imports) {
    if (!izinkan.has(`${imp.module}.${imp.name}`)) {
      throw new Error(`import tak diizinkan: ${imp.module}.${imp.name}`)
    }
  }
 
  return {
    env: {
      log: (n) => console.log(n),
    },
  }
}

Sebelum instansiasi, cek seluruh permintaan imports modul — siapa yang boleh menyediakan apa. Modul yang meminta import mencurigakan harus ditolak.

Menghindari unsafe di Interop

Rust punya unsafe — dan interop Wasm sering memaksanya. Prinsip keamanannya:

  1. Satu titik unsafe — bungkus semua unsafe di satu modul kecil, tidak tersebar.
  2. Validasi di batas — semua data yang datang dari JS diperiksa (panjang, alamat, range) sebelum dipakai.
  3. Tidak ada unsafe yang tidak perlu — jika bisa memakai wasm-bindgen safe API, pakai itu.
unsafe-terbatas.rs
// Bungkus akses raw dalam satu fungsi dengan guard
pub fn baca_byte(mem: &Memory, ptr: u32, len: u32, i: u32) -> u32 {
    if i >= len {
        return 0 // out-of-bounds: tolak, jangan crash
    }
    let bytes = unsafe {
        mem.view().data_unchecked() // satu-satunya titik unsafe
    };
    bytes[(ptr + i) as usize] as u32
}

Supply-Chain: cargo audit dan Sahabatnya

Modul yang aman bisa dibangun dari dependency yang rentan. Audit otomatis adalah bagian wajib CI:

Install dan jalankan cargo-audit
cargo install cargo-audit
cargo audit

Cek tambahan yang direkomendasikan:

  • cargo deny — kebijakan lisensi + advisory + sumber crate.
  • wasm-opt --strip-debug — pastikan tidak ada info debugging yang bocor.
  • Pinning dependency — build yang reproducible dengan lockfile.
100%

Best Practice: Checklist Keamanan

Sebelum menjalankan modul Wasm yang tidak dipercaya di produksi:

  • Audit imports modul — hanya izinkan yang diperlukan.
  • Batasi capability WASI (--dir, --env, --listen).
  • Set CSP dengan wasm-unsafe-eval, bukan 'unsafe-eval'.
  • Jalankan cargo audit + cargo deny di CI.
  • Isolasi instance — satu instance per tenant, bukan berbagi.
  • Batasi resource (CPU/memori/timeout) di level runtime.

Warning

Sandbox yang kuat tidak menghapus tanggung jawab host: fungsi yang di-import (log, network, file) tetap bisa disalahgunakan. Perlakukan imports seperti API publik — validasi input, batasi ukuran, dan jangan pernah mengekspos kredensial tanpa kontrol.

Penutup

Pada episode 16 ini, kalian telah memahami model keamanan WebAssembly dan praktik pengamanannya.

Inti yang harus dibawa pulang:

  • Isolasi memory per-instance + verifikasi statis = sandbox yang aman secara arsitektur.
  • WASI memakai capability-based security — deny by default, tanpa raw syscall.
  • Validasi imports sebelum instansiasi; batasi apa yang bisa dilakukan modul.
  • Bungkus unsafe, jaga satu titik, dan audit supply-chain di CI.

Di episode 17 selanjutnya kita akan membahas networking — WASI wasi:http untuk outbound requests, serve HTTP via runtime, interop fetch di Node, serta streaming async WASI 0.3 untuk real-time dan WebTransport eksperimental. Sampai jumpa di episode 17!

Belajar WebAssembly - Keamanan & Sandboxing | Belajar Web Assembly