Mengambil Kunci Bytecode Array dari Backend
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. DenganvmAsyncExecutoraktif, ia boleh mengembalikanPromise; 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.
vmBytecodeArrayEncodingKeydikombinasikan dengan kunci internal yang diturunkan obfuscator, dan larik bytecode dienkode dengan kunci campuran hasilnya. - Saat runtime. Nilai yang di-resolve oleh
vmBytecodeArrayEncodingKeyGetterAnda — 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
);
});
