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

बैकएंड से बाइटकोड ऐरे कुंजी लाना

बैकएंड से बाइटकोड ऐरे कुंजी लाना

Pro
v7.3.0+

VM बाइटकोड डिक्रिप्शन कुंजी को क्लाइंट से बाहर रखें: उसे लोड के समय एक असिंक्रोनस की-गेटर के ज़रिए अपने बैकएंड से लाएँ और ऑथेंटिकेशन के पीछे सुरक्षित रखें, ताकि चोरी हुआ बंडल बेकार रहे।

समस्या

vmBytecodeArrayEncoding VM बाइटकोड को एक कुंजी से एन्क्रिप्ट करता है। अगर वह कुंजी बंडल के अंदर ही चली जाए, तो जिसके पास फ़ाइल है उसके पास उसे डिक्रिप्ट करने के लिए सब कुछ मौजूद है। vmBytecodeArrayEncodingKeyGetter कुंजी को कहीं और रखने और रनटाइम पर बनाने की सुविधा देता है — लेकिन सिंक्रोनस गेटर सिर्फ़ वही पढ़ सकता है जो क्लाइंट पर पहले से मौजूद हो (कोई ग्लोबल, कुकी, localStorage)। कुंजी को अपने सर्वर से लाने के लिए — ताकि आप उसे ऑथेंटिकेशन के पीछे रख सकें और रद्द कर सकें — गेटर का असिंक्रोनस होना ज़रूरी है।

समाधान

vmAsyncExecutor (v7.3.0+) चालू करें। एसिंक एक्ज़ीक्यूटर के साथ की-गेटर Promise लौटा सकता है, इसलिए वह VM चलने से पहले आपके बैकएंड से कुंजी fetch कर सकता है। तीन विकल्प मिलकर काम करते हैं:

  • vmBytecodeArrayEncoding: true — बाइटकोड ऐरे को एन्क्रिप्ट करता है।
  • vmBytecodeArrayEncodingKey — कंपाइल समय पर इस्तेमाल होने वाली कुंजी (आपके सर्वर पर रखी जाती है, बंडल में नहीं)।
  • vmBytecodeArrayEncodingKeyGetter — एक JS एक्सप्रेशन जो रनटाइम पर वही कुंजी लौटाता है। vmAsyncExecutor चालू होने पर यह Promise लौटा सकता है; उसके बिना गेटर को कुंजी सिंक्रोनस रूप से लौटानी होगी।

क्लाइंट ऑब्फ़स्केशन कॉन्फ़िग

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())'
});

गेटर एक्सप्रेशन ज्यों का त्यों एम्बेड होता है और ब्राउज़र में इवैल्युएट किया जाता है। कंपाइल-समय वाली vmBytecodeArrayEncodingKey को अपने क्लाइंट रेपो से बाहर रखें — उसे बिल्ड के समय किसी एनवायरनमेंट वैरिएबल या सीक्रेट से इंजेक्ट करें, और नीचे दिए एंडपॉइंट से ठीक वही स्ट्रिंग सर्व करें।

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

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

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

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

सर्वर साइड

एंडपॉइंट यह तय करता है कि कौन-सी कुंजी लौटानी है — यह इस पर निर्भर करता है कि आपका ऐप्लिकेशन किस पर भरोसा करता है: कोई वैध सेशन, अपेक्षित Origin या Referer, लाइसेंस जाँच, वगैरह। ख़ास बात यह है: अविश्वसनीय कॉलर्स को अस्वीकार करने के बजाय एक ग़लत कुंजी लौटाएँ। तब बाइटकोड कचरे में डिकोड होता है और सुरक्षित कोड अपने आप विफल हो जाता है, जो एक स्पष्ट 401 से कहीं ज़्यादा छिपा हुआ तरीका है — क्योंकि 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
    );
});