दस्तावेज़ीकरण
/
रेसिपीज़
/

बाइटकोड ऐरे एन्कोडिंग कुंजी

बाइटकोड ऐरे एन्कोडिंग कुंजी को बाहर निकालना

Pro

vmBytecodeArrayEncodingKey के साथ अपनी खुद की VM बाइटकोड एन्क्रिप्शन कुंजी दें और उसे रनटाइम पर एक कुंजी गेटर के जरिए वापस सौंपें — बंडल से बाहर रखी गई, क्लाइंट स्टोरेज से पढ़ी गई, या अपने बैकएंड से लाई गई।

ये विकल्प क्या करते हैं

vmBytecodeArrayEncoding VM बाइटकोड ऐरे को एन्क्रिप्ट करता है ताकि वह आउटपुट में सादे पाठ के रूप में न रहे। डिफ़ॉल्ट रूप से एन्क्रिप्शन कुंजी परिवेश से व्युत्पन्न होती है और क्लाइंट पर पुनर्निर्मित की जाती है, इसलिए आपको उसे कभी संभालना नहीं पड़ता। यह सुविधाजनक है, लेकिन कुंजी सामग्री फिर भी बंडल में ही रहती है।

दो विकल्प आपको कुंजी को बंडल से बाहर निकालने और उसे स्वयं नियंत्रित करने देते हैं:

  • vmBytecodeArrayEncodingKey — वह कुंजी जो आप कंपाइल समय पर देते हैं। सेट होने पर, इसे डिफ़ॉल्ट परिवेश-व्युत्पन्न कुंजी के बजाय उपयोग किया जाता है, और यह ऑब्फस्केटेड आउटपुट में एम्बेड नहीं की जाती।
  • vmBytecodeArrayEncodingKeyGetter — एक JavaScript अभिव्यक्ति जो रनटाइम पर वही कुंजी लौटाती है। यह यथावत एम्बेड की जाती है और ऑब्फस्केटेड कोड लोड होने पर ब्राउज़र में मूल्यांकित की जाती है।

मुख्य बात पृथक्करण है: चूँकि कुंजी कोड में नहीं है, बंडल का विशुद्ध रूप से स्थैतिक स्कैन उसे पुनर्प्राप्त नहीं कर सकता। कोड को चलने के लिए उसे रनटाइम पर मौजूद रहना ही पड़ता है, इसलिए वह वास्तव में गुप्त नहीं है — पर आप तय करते हैं कि वह कहाँ से आती है और उसे कौन देख सकता है।

दोनों कुंजियाँ कैसे संयुक्त होती हैं

आपकी कुंजी को कभी अकेले उपयोग नहीं किया जाता — दोनों ओर इसे एक आंतरिक कुंजी के साथ मिलाया जाता है जिसे ऑब्फस्केटर नियंत्रित करता है:

  • कंपाइल समय। vmBytecodeArrayEncodingKey को एक आंतरिक कुंजी के साथ संयुक्त किया जाता है जिसे ऑब्फस्केटर व्युत्पन्न करता है, और बाइटकोड ऐरे को परिणामी मिश्रित कुंजी से एन्कोड किया जाता है।
  • रनटाइम। जिस मान पर आपका vmBytecodeArrayEncodingKeyGetter हल होता है, उसे उसी आंतरिक कुंजी के साथ संयुक्त किया जाता है, जो विभिन्न रनटाइम कारकों से क्लाइंट पर पुनर्निर्मित होती है, ताकि बाइटकोड को डिकोड किया जा सके।

चूँकि दोनों ओर आपकी कुंजी को आंतरिक कुंजी के साथ मिलाया जाता है, गेटर को बिल्कुल वही स्ट्रिंग लौटानी चाहिए जो आपने vmBytecodeArrayEncodingKey के रूप में दी थी। कोई भी हिस्सा अकेले पर्याप्त नहीं है: आंतरिक कुंजी के बिना आपकी कुंजी बाइटकोड को डिकोड नहीं कर सकती, और आपकी कुंजी के बिना आंतरिक कुंजी बेकार है — यही कारण है कि यह नियंत्रित करना कि आपकी कुंजी किसे मिलती है, वही वास्तव में कोड की रक्षा करता है।

रनटाइम पर कुंजी प्रदान करना

डिफ़ॉल्ट रूप से गेटर समकालिक (synchronous) होता है: ऑब्फस्केटेड कोड लोड होते ही अभिव्यक्ति को तुरंत कुंजी लौटानी चाहिए। इसे किसी भी ऐसे स्रोत से पढ़ें जो पहले से क्लाइंट पर मौजूद है — एक कुकी, 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"

अपने बैकएंड से कुंजी लाना (async)

आवश्यक है vmAsyncExecutor · v7.3.0+

एक समकालिक गेटर केवल वही पढ़ सकता है जो पहले से क्लाइंट पर है। कुंजी को अपने सर्वर से लाने के लिए — ताकि आप उसे प्रमाणीकरण के पीछे रख सकें और निरस्त कर सकें — गेटर को असमकालिक (asynchronous) होना पड़ता है, और उसके लिए vmAsyncExecutor आवश्यक है। async executor सक्षम होने पर, गेटर एक Promise लौटा सकता है, और VM चलने से पहले उसकी प्रतीक्षा करता है।

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, या एक खाली स्ट्रिंग लौटाए — तो डिक्रिप्शन एक गलत कीस्ट्रीम उत्पन्न करता है और कोड रनटाइम पर बकवास आउटपुट या एक साधारण रनटाइम त्रुटि के साथ विफल हो जाता है।

जानबूझकर कोई विशिष्ट, कुंजी-विशेष त्रुटि संदेश नहीं है: एक विफल कुंजी किसी भी अन्य रनटाइम दोष से अभेद्य होती है। इसलिए जब कोई VM-संरक्षित बंडल केवल इस विकल्प के सक्रिय होने पर ही अपवाद फेंके, तो पहले कुंजी पथ की जाँच करें — कि गेटर पृष्ठ पर हल होता है, एक गैर-खाली स्ट्रिंग लौटाता है, और वही मान लौटाता है जिसके साथ आपने बिल्ड किया था।