إخراج مفتاح ترميز مصفوفة البايت كود إلى الخارج
زوّد مفتاح تشفير البايت كود الخاص بالآلة الافتراضية بنفسك عبر vmBytecodeArrayEncodingKey وأعِده وقت التشغيل من خلال دالة جلب المفتاح — يبقى خارج الحزمة، أو يُقرأ من تخزين العميل، أو يُجلب من الخادم الخلفي.
ما الذي تفعله هذه الخيارات
يقوم vmBytecodeArrayEncoding بتشفير مصفوفة البايت كود الخاصة بالآلة الافتراضية حتى لا تظهر في
المخرجات كنص صريح. افتراضيًا، يُشتق مفتاح التشفير من البيئة ويُعاد بناؤه على جهة العميل، لذا لا تتعامل معه أبدًا. هذا مريح،
لكن مادة المفتاح لا تزال موجودة داخل الحزمة.
يتيح لك خياران إخراج المفتاح من الحزمة والتحكم به بنفسك:
vmBytecodeArrayEncodingKey— المفتاح الذي تزوّده وقت الترجمة. عند تعيينه، يُستخدم بدلًا من المفتاح الافتراضي المشتق من البيئة، ولا يُضمَّن في المخرجات المشوَّشة.vmBytecodeArrayEncodingKeyGetter— تعبير JavaScript يُرجع المفتاح نفسه وقت التشغيل. يُضمَّن حرفيًا ويُقيَّم في المتصفح عند تحميل الكود المشوَّش.
الهدف هو الفصل: بما أن المفتاح ليس ضمن الكود، فإن الفحص الساكن البحت للحزمة لا يمكنه استعادته. لا يزال يجب أن يكون حاضرًا وقت التشغيل حتى يعمل الكود، لذا فهو ليس سريًا حقًا — لكنك تقرّر من أين يأتي ومن يمكنه رؤيته.
كيف يتّحد المفتاحان
لا يُستخدم مفتاحك بمفرده أبدًا — فعلى كلا الجانبين يُمزج بمفتاح داخلي يتحكم به المشوِّش:
- وقت الترجمة. يُدمج
vmBytecodeArrayEncodingKeyمع مفتاح داخلي يشتقّه المشوِّش، وتُرمَّز مصفوفة البايت كود بالمفتاح الممزوج الناتج. - وقت التشغيل. تُدمج القيمة التي تُرجعها
vmBytecodeArrayEncodingKeyGetterمع المفتاح الداخلي نفسه، المُعاد بناؤه على جهة العميل من عوامل تشغيل مختلفة، لفك ترميز البايت كود.
بما أن كلا الجانبين يمزجان مفتاحك مع المفتاح الداخلي، يجب أن تُرجع دالة الجلب السلسلة النصية نفسها تمامًا التي مررتها
إلى vmBytecodeArrayEncodingKey. لا يكفي أي جزء بمفرده: مفتاحك بدون المفتاح الداخلي لا يمكنه فك ترميز البايت كود،
والمفتاح الداخلي عديم الفائدة بدون مفتاحك — ولهذا فإن التحكم بمن يتلقى مفتاحك هو ما يحمي الكود فعليًا.
تزويد المفتاح وقت التشغيل
افتراضيًا، تكون دالة الجلب متزامنة: يجب أن يُرجع التعبير المفتاح فورًا عند تحميل الكود المشوَّش. اقرأه من أي مصدر
موجود بالفعل على جهة العميل — ملف تعريف ارتباط، أو localStorage، أو متغير عام، أو عنصر DOM محقون من الخادم.
JavaScriptObfuscator.obfuscate(sourceCode, {
vmObfuscation: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: process.env.VM_KEY, // e.g. 'mySecretKey123'
vmBytecodeArrayEncodingKeyGetter: "window.__VM_KEY__" // returns the key at runtime
});
يجب أن يكون المفتاح موجودًا قبل تشغيل الكود المشوَّش:
// Set by a different script, a server-injected inline script, etc.
window.__VM_KEY__ = 'mySecretKey123';
تعمل المصادر المتزامنة الأخرى بالطريقة نفسها — اختر أيًا منها يملؤه تطبيقك بالفعل:
// 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"
جلب المفتاح من الخادم الخلفي (غير متزامن)
يتطلب vmAsyncExecutor · v7.3.0+لا يمكن لدالة الجلب المتزامنة إلا قراءة ما هو موجود بالفعل على جهة العميل. لجلب المفتاح من خادمك — بحيث يمكنك
تقييده خلف المصادقة وإبطاله — يجب أن تكون دالة الجلب غير متزامنة، وهذا يتطلب
vmAsyncExecutor. عند تفعيل المنفّذ غير المتزامن، يمكن لدالة الجلب أن تُرجع
Promise، وتنتظره الآلة الافتراضية قبل التشغيل.
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())'
});
على الخادم، قرّر أي مفتاح تُرجعه بناءً على ما يثق به تطبيقك — جلسة صالحة، أو Origin أو Referer متوقّع، أو فحص
ترخيص، وهكذا. الحيلة: بدلًا من رفض المستدعين غير الموثوقين، أرجِع مفتاحًا خاطئًا. عندئذٍ يُفكّ ترميز البايت كود إلى
بيانات لا معنى لها ويفشل الكود المحمي من تلقاء نفسه، وهو أخفى من خطأ 401 واضح يُخبر المهاجم بالضبط بما يجب تجاوزه.
// 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
);
});
قدّم من نقطة النهاية هذه السلسلة النصية نفسها تمامًا التي مررتها إلى vmBytecodeArrayEncodingKey وقت البناء. أي نسخة
من الحزمة تعمل خارج بيئتك تحصل على المفتاح الخادع، فتُفكّ تشفيرها إلى لا شيء، وتبقى خاملة.
عندما لا يتطابق المفتاح
لا يعمل الكود المشوَّش إلا عندما تُرجع دالة الجلب تمامًا المفتاح نفسه المستخدَم أثناء التشويش. إذا اختلف المفتاحان
— أو أرجعت دالة الجلب undefined أو null أو سلسلة فارغة — فإن فك التشفير يُنتج تدفّق مفاتيح خاطئًا ويفشل الكود
وقت التشغيل بمخرجات لا معنى لها أو بخطأ تشغيل عادي.
لا توجد عمدًا رسالة خطأ مميزة خاصة بالمفتاح: المفتاح الفاشل لا يمكن تمييزه عن أي عطل تشغيل آخر. لذا عندما تُطلق حزمة محمية بالآلة الافتراضية استثناءً فقط عند تفعيل هذا الخيار، تحقّق من مسار المفتاح أولًا — من أن دالة الجلب تُقيَّم على الصفحة، وتُرجع سلسلة غير فارغة، وتُرجع القيمة نفسها التي بنيت بها.
