Dokumentasi
/
Resep
/

Mengambil Kunci Bytecode Array dari Backend

Mengambil Kunci Bytecode Array dari Backend

Pro
v7.3.0+

Jauhkan kunci dekripsi bytecode VM dari sisi klien: ambil dari backend Anda saat pemuatan menggunakan key getter asinkron, yang dilindungi autentikasi sehingga bundel yang dicuri menjadi tidak berguna.

Masalahnya

vmBytecodeArrayEncoding mengenkripsi bytecode VM dengan sebuah kunci. Jika kunci tersebut ikut dikirim di dalam bundel, siapa pun yang memiliki berkasnya juga memiliki segala hal yang diperlukan untuk mendekripsinya. Sebuah vmBytecodeArrayEncodingKeyGetter memungkinkan kunci tersebut berada di tempat lain dan dihasilkan saat runtime — tetapi getter sinkron hanya dapat membaca apa yang sudah ada di sisi klien (variabel global, cookie, localStorage). Untuk mengambil kunci dari server Anda — sehingga Anda dapat melindunginya di balik autentikasi dan mencabutnya — getter tersebut harus bersifat asinkron.

Solusinya

Aktifkan vmAsyncExecutor (v7.3.0+). Dengan executor async, key getter boleh mengembalikan Promise, sehingga ia dapat mem-fetch kunci dari backend Anda sebelum VM berjalan. Tiga opsi bekerja bersama:

  • vmBytecodeArrayEncoding: true — mengenkripsi larik bytecode.
  • vmBytecodeArrayEncodingKey — kunci yang digunakan pada saat kompilasi (disimpan di server Anda, bukan di dalam bundel).
  • vmBytecodeArrayEncodingKeyGetter — sebuah ekspresi JS yang mengembalikan kunci yang sama itu saat runtime. Dengan vmAsyncExecutor aktif, ia boleh mengembalikan Promise; tanpanya, getter harus mengembalikan kunci secara sinkron.

Konfigurasi obfuskasi klien

JavaScriptObfuscator.obfuscate(sourceCode, {
    vmObfuscation: true,
    vmAsyncExecutor: true,
    vmBytecodeArrayEncoding: true,
    vmBytecodeArrayEncodingKey: process.env.VM_KEY,            // e.g. 'mySecretKey123'
    vmBytecodeArrayEncodingKeyGetter:
        'fetch("/api/vm-key", { credentials: "include" }).then((res) => res.text())'
});

Ekspresi getter disematkan apa adanya dan dievaluasi di peramban. Jauhkan vmBytecodeArrayEncodingKey yang digunakan saat kompilasi dari repo klien Anda — injeksikan dari variabel lingkungan atau secret saat build, dan sajikan string yang persis sama dari endpoint di bawah ini.

Cara kedua kunci bekerja

Kunci Anda tidak pernah digunakan sendirian — pada kedua sisi, kunci tersebut dicampur dengan kunci internal yang dikendalikan obfuscator:

  • Saat kompilasi. vmBytecodeArrayEncodingKey dikombinasikan dengan kunci internal yang diturunkan obfuscator, dan larik bytecode dienkode dengan kunci campuran hasilnya.
  • Saat runtime. Nilai yang di-resolve oleh vmBytecodeArrayEncodingKeyGetter Anda — yang dikembalikan server Anda — dikombinasikan dengan kunci internal yang sama, yang direkonstruksi di sisi klien dari berbagai faktor runtime, untuk mendekode bytecode.

Karena kedua sisi mencampur kunci Anda dengan kunci internal, getter harus di-resolve menjadi string yang persis sama dengan yang Anda berikan sebagai vmBytecodeArrayEncodingKey. Tidak ada satu bagian pun yang cukup sendirian: kunci Anda tanpa kunci internal tidak dapat mendekode bytecode, dan kunci internal tidak berguna tanpa kunci Anda — itulah sebabnya menyajikan kunci Anda hanya kepada pemanggil terautentikasi membuat bundel yang dicuri tidak berguna.

Sisi server

Endpoint memutuskan kunci mana yang dikembalikan berdasarkan apa pun yang dipercayai aplikasi Anda — sesi yang valid, Origin atau Referer yang diharapkan, pemeriksaan lisensi, dan sebagainya. Ada trik: alih-alih menolak pemanggil yang tidak tepercaya, kembalikan kunci yang salah. Bytecode kemudian akan terdekode menjadi sampah dan kode yang terlindungi gagal dengan sendirinya, yang lebih tersembunyi ketimbang respons 401 yang gamblang dan justru memberi tahu penyerang persis apa yang harus dilewati.

// Express example — the exact checks depend on your app
app.get('/api/vm-key', (req, res) => {
    const origin = req.get('origin');
    const trusted =
        req.session?.user &&                       // a valid session, and
        origin === 'https://app.example.com';      // the expected production origin

    res.type('text/plain').send(
        // Real key for valid users; a decoy for everyone else
        // (no session, or a localhost / unexpected origin).
        trusted ? process.env.VM_KEY : process.env.VM_DECOY_KEY
    );
});