Mengeksternalkan Kunci Enkoding Array Bytecode
Sediakan kunci enkripsi bytecode VM Anda sendiri dengan vmBytecodeArrayEncodingKey dan serahkan kembali saat runtime melalui sebuah key getter — disimpan di luar bundle, dibaca dari penyimpanan klien, atau diambil dari backend Anda.
Apa yang dilakukan opsi-opsi ini
vmBytecodeArrayEncoding mengenkripsi array bytecode VM agar tidak berada di
output sebagai teks polos. Secara bawaan, kunci enkripsi diturunkan dari lingkungan dan direkonstruksi di sisi klien,
sehingga Anda tidak pernah menanganinya. Itu praktis, tetapi materi kunci tetap tersimpan di dalam bundle.
Dua opsi memungkinkan Anda mengeluarkan kunci dari bundle dan mengendalikannya sendiri:
vmBytecodeArrayEncodingKey— kunci yang Anda sediakan saat kompilasi. Ketika diset, kunci ini digunakan sebagai pengganti kunci bawaan yang diturunkan dari lingkungan, dan tidak disematkan ke dalam output terobfuskasi.vmBytecodeArrayEncodingKeyGetter— sebuah ekspresi JavaScript yang mengembalikan kunci yang sama saat runtime. Ekspresi ini disematkan secara verbatim dan dievaluasi di peramban saat kode terobfuskasi dimuat.
Intinya adalah pemisahan: karena kunci tidak berada di dalam kode, pemindaian statis murni atas bundle tidak dapat memulihkannya. Kunci tetap harus hadir saat runtime agar kode dapat berjalan, jadi ia tidak benar-benar rahasia — tetapi Anda yang menentukan dari mana asalnya dan siapa yang boleh melihatnya.
Bagaimana kedua kunci digabungkan
Kunci Anda tidak pernah digunakan sendirian — di kedua sisi ia dicampur dengan kunci internal yang dikendalikan oleh obfuscator:
- Saat kompilasi.
vmBytecodeArrayEncodingKeydigabungkan dengan kunci internal yang diturunkan oleh obfuscator, dan array bytecode dienkode dengan kunci campuran yang dihasilkan. - Saat runtime. Nilai yang di-resolve oleh
vmBytecodeArrayEncodingKeyGetterAnda digabungkan 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 mengendalikan siapa yang menerima kunci Anda-lah yang sebenarnya melindungi kode.
Menyediakan kunci saat runtime
Secara bawaan getter bersifat sinkron: ekspresi harus mengembalikan kunci seketika saat kode terobfuskasi dimuat.
Baca dari sumber apa pun yang sudah ada di sisi klien — sebuah cookie, localStorage, sebuah variabel global, atau
sebuah elemen DOM yang diinjeksikan server.
JavaScriptObfuscator.obfuscate(sourceCode, {
vmObfuscation: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: process.env.VM_KEY, // e.g. 'mySecretKey123'
vmBytecodeArrayEncodingKeyGetter: "window.__VM_KEY__" // returns the key at runtime
});
Kunci harus sudah ada sebelum kode terobfuskasi berjalan:
// Set by a different script, a server-injected inline script, etc.
window.__VM_KEY__ = 'mySecretKey123';
Sumber sinkron lainnya bekerja dengan cara yang sama — pilih yang mana pun yang sudah diisi oleh aplikasi Anda:
// From a cookie
vmBytecodeArrayEncodingKeyGetter: "document.cookie.match(/vmKey=([^;]+)/)?.[1]"
// From localStorage
vmBytecodeArrayEncodingKeyGetter: "localStorage.getItem('vmKey')"
// From a server-injected meta tag
vmBytecodeArrayEncodingKeyGetter: "document.querySelector('meta[name=\"vm-key\"]').content"
// From a nested object
vmBytecodeArrayEncodingKeyGetter: "window.config.encryption.key"
Mengambil kunci dari backend Anda (async)
Membutuhkan vmAsyncExecutor · v7.3.0+Getter sinkron hanya dapat membaca apa yang sudah ada di klien. Untuk mengambil kunci dari server Anda — sehingga
Anda dapat membatasinya di balik autentikasi dan mencabutnya — getter harus asinkron, dan itu membutuhkan
vmAsyncExecutor. Dengan async executor diaktifkan, getter boleh mengembalikan
sebuah Promise, dan VM menunggunya sebelum berjalan.
JavaScriptObfuscator.obfuscate(sourceCode, {
vmObfuscation: true,
vmAsyncExecutor: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: process.env.VM_KEY, // kept on your server, not in the bundle
vmBytecodeArrayEncodingKeyGetter:
'fetch("/api/vm-key", { credentials: "include" }).then((res) => res.text())'
});
Di server, tentukan kunci mana yang dikembalikan berdasarkan apa pun yang dipercaya aplikasi Anda — sesi yang valid,
Origin atau Referer yang diharapkan, pemeriksaan lisensi, dan seterusnya. Kejutannya: alih-alih menolak pemanggil
yang tidak tepercaya, kembalikan kunci yang salah. Bytecode kemudian terdekode menjadi sampah dan kode terlindungi
gagal dengan sendirinya, yang lebih tersamar daripada 401 yang kentara yang 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
);
});
Sajikan string yang persis sama dari endpoint ini dengan yang Anda berikan sebagai vmBytecodeArrayEncodingKey saat
build. Sebuah salinan bundle yang berjalan di luar lingkungan Anda mendapatkan kunci umpan, terdekripsi menjadi tidak
ada apa-apa, dan menjadi mati.
Ketika kunci tidak cocok
Kode terobfuskasi hanya bekerja ketika getter mengembalikan persis kunci yang sama dengan yang digunakan selama
obfuskasi. Jika kunci berbeda — atau getter mengembalikan undefined, null, atau string kosong — dekripsi
menghasilkan keystream yang salah dan kode gagal saat runtime dengan output sampah atau kesalahan runtime biasa.
Secara sengaja tidak ada pesan kesalahan yang khas dan spesifik-kunci: kunci yang gagal tidak dapat dibedakan dari kesalahan runtime lainnya. Jadi ketika bundle yang dilindungi VM melempar hanya begitu opsi ini aktif, periksa jalur kunci terlebih dahulu — bahwa getter di-resolve di halaman, mengembalikan string yang tidak kosong, dan mengembalikan nilai yang sama dengan yang Anda gunakan saat build.
