1 पॉइंट द्वारा GN⁺ 2024-07-08 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • @sebastianwessel/quickjs एक TypeScript पैकेज है जो QuickJS engine को WebAssembly में compile किए गए sandbox के भीतर JavaScript और TypeScript code को सुरक्षित रूप से चलाता है
  • इसका फोकस untrusted code को isolate करके चलाने पर है, और QuickJS WebAssembly sandbox के ज़रिए हल्का और तेज़ execution environment देता है
  • इसमें basic Node.js module support, virtual file system mount, custom Node module mount, fetch client, test runner, और Chai-आधारित expect शामिल हैं
  • उपयोग उदाहरण में loadQuickJs() से QuickJS wasm को एक बार load करने के बाद runSandboxed() और evalCode() से code चलाया जाता है, और allowFetch, allowFs, env जैसे options दिए जाते हैं
  • TypeScript application में बाहरी JavaScript code चलाने की ज़रूरत रखने वाले developer इसे isolation, performance, और API simplicity को साथ लेकर चलने वाले execution environment के रूप में उपयोग कर सकते हैं

QuickJS WebAssembly सैंडबॉक्स पैकेज

  • @sebastianwessel/quickjs एक TypeScript पैकेज है जो JavaScript और TypeScript code को WebAssembly sandbox के भीतर चलाने की सुविधा देता है
  • यह QuickJS engine को WebAssembly में compile करके उपयोग करता है, और untrusted code को isolated environment में चलाने के लिए बनाया गया है
  • यह पैकेज हल्के और तेज़ QuickJS engine का उपयोग करके code execution के लिए मज़बूत environment प्रदान करता है
  • यह पूर्ण documentation, examples, और online playground प्रदान करता है

उपलब्ध सुविधाएँ

  • सुरक्षित execution: untrusted JavaScript और TypeScript code को सुरक्षित और isolated environment में चलाता है
  • बेसिक Node.js modules: सामान्य use case के लिए standard Node.js modules का basic support देता है
  • फ़ाइल सिस्टम: virtual file system को mount किया जा सकता है
  • Custom Node modules: user-defined Node modules को mount किया जा सकता है
  • Network calls: fetch client देता है जिससे http(s) calls की जा सकती हैं
  • Test support: test runner और Chai-आधारित expect शामिल है
  • Performance और integration: QuickJS engine की हल्केपन और दक्षता का लाभ उठाता है और मौजूदा TypeScript project में आसानी से integrate किया जा सकता है
  • सरल API: sandbox के भीतर JavaScript और TypeScript code चलाने और manage करने के लिए user-friendly API देता है

बेसिक उपयोग प्रवाह

  • पहले @jitl/quickjs-ng-wasmfile-release-sync से variant import किया जाता है, और @sebastianwessel/quickjs से loadQuickJs और SandboxOptions उपयोग किए जाते हैं
  • loadQuickJs(variant) QuickJS wasm को load और initialize करता है, और चूँकि यह काम resource-intensive है, इसलिए जहाँ संभव हो इसे केवल एक बार करना recommended है
  • loadQuickJs() runSandboxed लौटाता है, जिसका बाद में sandbox execution के लिए उपयोग होता है
  • SandboxOptions उदाहरण में ये options शामिल हैं
    • allowFetch: true: code में fetch inject करता है और data request की अनुमति देता है
    • allowFs: true: virtual file system को mount करता है और node:fs module उपलब्ध कराता है
    • env: sandbox code में उपयोग के लिए environment variable values पास करता है

execution उदाहरण में संभव व्यवहार

  • sandbox के भीतर का code path से join import करता है और join('src','dist') कॉल करके host system log में src/dist आउटपुट करता है
  • env.MY_ENV_VAR पढ़कर host system log में "env var value" आउटपुट करता है
  • new URL('https://example.com') से URL बनाता है और fetch(url) कॉल करने के बाद f.text() का result लौटाता है
  • code को runSandboxed(async ({ evalCode }) => evalCode(code), options) के रूप में चलाया जाता है
  • result उदाहरण { ok: true, data: '<!doctype html>\n<html>\n[....]</html>\n' } के रूप में है

लाइसेंस और उपयुक्त उपयोग

  • यह project MIT License के तहत उपलब्ध है
  • TypeScript application के भीतर JavaScript code को सुरक्षित रूप से चलाना चाहने वाले developers के लिए यह उपयुक्त है
  • QuickJS WebAssembly sandbox के ज़रिए यह performance और safety दोनों देने वाला execution environment प्रदान करता है

1 टिप्पणियां

 
GN⁺ 2024-07-08
Hacker News की राय
  • quickjs-emscripten runtime library के लेखक के रूप में, quickjs-emscripten के लिए बनाई गई ergonomic standard library style मुझे पसंद आई
    उत्सुक हूं कि क्या इसे browser या bundler में चलाकर देखा गया है। variant name को string के रूप में लेकर import(variantName) में dynamically पास करने का तरीका Webpack जैसे tools के साथ अच्छी तरह काम नहीं कर सकता
    Security warning: यह library guest के untrusted code को host fetch function जैसी cookies के साथ fetch call करने देती है। fetch enable करके untrusted code नहीं चलाना चाहिए
    अगर sandbox के अंदर का code host context के रूप में authenticated arbitrary HTTP API call कर सकता है, तो वह “sandbox” नहीं है
    quickjs-emscripten low-level है और magic जैसी features से बचता है, इसका कारण यह है कि हम confidence से कह सकें कि जो API हम देते हैं वे सुरक्षित हैं। magic जैसी serialization या आसान network/filesystem access features की requests हम आमतौर पर reject करते हैं, क्योंकि ऐसे code में security mistakes होना आसान होता है
    untrusted code चलाते समय सिर्फ sandbox itself नहीं, बल्कि sandbox को expose किए गए API के लिए लिखे गए code का भी सावधानी से audit करना चाहिए
    किसी दूसरे HN user का Fetch cookies के बारे में पूछा गया comment देखकर संभावित security issue का पता चला
    आगे पढ़ने के लिए: Figma plugin sandbox security लेख https://www.figma.com/blog/how-we-built-the-figma-plugin-sys..., https://www.figma.com/blog/an-update-on-plugin-security/, Quickjs-emscripten README https://github.com/justjake/quickjs-emscripten

    • iframe का इस्तेमाल करने पर, इस library का इस्तेमाल हो या न हो, क्या fetch cookie issue को रोका जा सकता है—यह जानना चाहूंगा। या फिर यह iframe में भी अब भी issue रहता है?
  • सर्वर साइड और ब्राउज़र साइड दोनों पर JavaScript को sandbox करने के कई तरीके हैं, लेकिन DOM access को “sandbox” करने का कोई तरीका है या नहीं, यह नहीं पता
    उदाहरण के लिए, किसी अविश्वसनीय third-party को पहले से तय स्थान के DOM elements तक ही access देना। मेरी जानकारी में इसे allow करने वाली इकलौती तकनीक iframe है, लेकिन अफसोस कि यह भारी और धीमी है
    मैं ऐसा app बना रहा हूँ जो plugins को host कर सके, लेकिन plugins को DOM access देने पर लगता है कि वे सचमुच कुछ भी कर सकते हैं

    • Salesforce इसे web components और patched ShadowRoot के combination से handle करता है। Shadow root reference रखने वाला code document के बाकी हिस्सों में बाहर न जा सके, ऐसा किया जाता है, और SES(Secure EcmaScript) से जुड़े सुरक्षित evaluation function के जरिए उन global objects को सीमित किया जाता है जिन तक अविश्वसनीय scripts पहुंच सकती हैं
      वह सुरक्षित evaluation function काफी कमाल का है। core शायद यहां है: https://github.com/Agoric/realms-shim/blob/v1.1.0/src/evalua...
      platform level पर इस समस्या को हल करने के लिए isolated web components का idea भी है: https://github.com/WICG/webcomponents/issues/1002
    • सबसे करीब Allen Wirfs-Brock का jsmirrors prototype है, लेकिन जहां तक मुझे पता है, DOM के लिए यह specification तक नहीं गया और शुरुआत में ऐसा करने का खास इरादा भी नहीं था। इसने सिर्फ JavaScript नाम के programming system के लिए capability को handle किया था
      jsmirrors से प्रेरित होकर आप खुद “dommirrors” जैसा कुछ try कर सकते हैं, लेकिन यह बड़ा काम है। jsmirrors को जैसा है वैसा इस्तेमाल करके आप जो चाहते हैं उसका कुछ हिस्सा हासिल करने का workaround भी है, लेकिन यह इस्तेमाल में सुविधाजनक नहीं है
      हालांकि DOM access को mediate या simulate करके देना लगभग निश्चित रूप से वह नहीं है जो आप सच में चाहते हैं। बेहतर है कि सामने वाले को असल में क्या करने की अनुमति देनी है, यह समझें और फिर सिर्फ वही capability दें जो उस behavior को संभव बनाती है
      उदाहरण के लिए, अगर आप उन्हें कहीं button जोड़ने देना चाहते हैं, तो लग सकता है कि parent element को anchor point की तरह देना और document.createElement से DOM node बनवाना चाहिए। लेकिन असल में आप उन्हें document.createElement access नहीं देना चाहते, बल्कि add-button capability देना चाहते हैं। इसलिए addButton implement कर दें
      और देखें: <https://news.ycombinator.com/item?id=30703531#30706060>
      जो लोग कहते हैं कि CSP इसी काम के लिए है, उनकी बात न सुनना बेहतर है। ऐसा नहीं है। सटीक कहें तो CSP अपने मूल लक्ष्य वाले use case में भी खराब design और user-hostile कचरा है, और मुझे लगता है कि इसे आज जिस तरह implement और extend किया गया है वैसा नहीं होना चाहिए था। इस पर निर्भर रहना जोखिम भरा है
    • सच में सुरक्षित access के लिए एकमात्र तरीका third-party code को किसी दूसरे domain का iframe देना और sandbox attribute सेट करना है
      parent page DOM content का size मापकर iframe का size एक तय सीमा के भीतर adjust कर सकता है, इसलिए इसे app UI में ज्यादा natural तरीके से integrate किया जा सकता है
      users के बीच exposure level और trust level के हिसाब से iframe के अंदर impersonation/phishing और clickjacking attempts से सावधान रहना चाहिए। Ideally frame को web requests बिल्कुल भी न कर पाने के लिए lock करना चाहिए, जिसका मतलब है कि image loading भी नहीं होगी
      ऐसा करने पर, मान लें user को fake password form में password डालने के लिए धोखा भी दे दिया जाए, तो भी data को frame के बाहर leak करने का कोई तरीका नहीं होगा
      iframe किन resource types को request कर सकता है, इसे सीमित करने का मुख्य तरीका Content-Security-Policy है, और इसके जरिए third-party images, scripts आदि सब बंद किए जा सकते हैं
      https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameE...
      https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
      दूसरे sandbox attributes भी on करें, और webcam जैसे privacy-sensitive DOM API access बंद करने चाहिए
      https://developer.mozilla.org/en-US/docs/Web/HTML/Element/if...
      https://developer.mozilla.org/en-US/docs/Web/Security/IFrame...
      https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Pe...
    • संभव तरीका शायद यह होगा कि third-party जो HTML render करना चाहता है उसे string के रूप में भेजने वाली API जोड़ी जाए, फिर कई libraries में से किसी एक से उसे parse किया जाए और parsed data के आधार पर DOM फिर से बनाया जाए
      इससे जिन HTML elements और attributes को allow करना है, उन्हें whitelist तक सीमित किया जा सकता है। native DOM event receiving तक allow करना हो तो जटिल हो जाएगा, लेकिन असंभव नहीं है
      event name string और event receive करने वाले element id को लेने वाली API जैसी चीज चाहिए होगी, फिर actual DOM में वह event detect करके उसी event को उपयोग हो रहे JavaScript sandbox के अंदर replicate करना होगा। उस sandbox के अंदर ऊपर बताई API तक access होना चाहिए
    • तुरंत सोचने पर इसे इस तरह किया जा सकता है: backend पर third-party code request करें और उस code को hash sequence से जोड़ दें
      backend पर HTML को dynamically modify करके ऐसा div tag डालें जिसका id value hash sequence हो। साथ ही HTML को modify करके अपने domain से third-party code request करने वाला script tag डालें, और tracking के लिए उस script tag के data attribute में hash value जोड़ दें

बैकएंड पर third-party code को बदलकर document. और window. के सभी instances को document.getElementById(hash_value). से replace करें, और सभी query selectors को #hash_value से शुरू करवाएँ
Element prototype के .parentNode को custom property से replace करके, दिए गए container से बाहर निकलने की कोशिशों की जांच और उन्हें block करना होगा
फिर HTML document को browser पर भेजें। third-party code टूट जाए तो भी ठीक है। constraints third party को बतानी होंगी, और server पर भेजने से पहले अपने code की testing उन्हें खुद करनी होगी
अहम बात सिर्फ यह है कि code dynamically दिए गए container से बाहर न जा सके। security violations खोजने के लिए इस हिस्से को नियमित रूप से test करना होगा
हो सकता है असल में काम न करे, लेकिन experiment करके देखना दिलचस्प होगा

  • संयोग से पिछले हफ्ते QuickJS आज़माया, और आखिर में isolated-vm पर आकर रुका। दोनों ने सुरक्षा संबंधी ज़रूरतें पूरी कीं, लेकिन setup, teardown और eval चलाने के overhead के मामले में isolated-vm का performance कहीं बेहतर था

  • दिलचस्प approach है। worker के जरिए isolation और JavaScript environment cleanup तकनीक इस्तेमाल करने वाली एक दूसरी JavaScript sandbox library[1] के लेखक के तौर पर, मुझे लगता है कि JavaScript को interpret करने का तरीका—यानी JavaScript के अंदर JavaScript, या इस मामले में WASM के अंदर JavaScript—सबसे ऊंचे स्तर का isolation देता है
    साथ ही यह host JavaScript virtual machine के bugs के सीधे exposure से भी बचाता है। अगर target Node है तो यह और अहम हो सकता है, क्योंकि कुछ नए trends को छोड़ दें तो Node.js, Deno के उलट, isolation और sandboxing को ध्यान में रखकर design किया गया नहीं लगता
    API देखने पर यह साफ नहीं दिखता कि createRuntime, fetch के अलावा host environment calls define कर सकता है या नहीं। यह feature काफी उपयोगी होगा, क्योंकि इससे बाहरी दुनिया से communication को सब-कुछ allow या सब-कुछ block करने के बजाय नियंत्रित तरीके से सीमित किया जा सकता है
    इसी तरह, browser support भी दिखता नहीं है। कम-से-कम esm.sh से जल्दी जांचने पर तो ऐसा ही लगा। यह भी उपयोगी feature हो सकता है
    overhead कितना है, यह जानने के लिए test करने वाला हूं, और जैसा ऊपर कहा, approach अपने-आप में काफी मजबूत लगती है
    [1] @exact-realty/lot

  • CPU अब इतने तेज हो गए हैं कि बात कुछ ऐसी लग रही है: चलो अब interpreter के अंदर interpreter चलाते हैं

  • QuickJS में JavaScript चलाने का फायदा मैं performance को नहीं कहूंगा। QuickJS, host JavaScript virtual machine से बिल्कुल compete नहीं करता
    हालांकि यह पुराने C interpreters या JavaScript में implement किए गए interpreters से तेज हो सकता है

    • अगर Node.js process startup time, script execution time से ज्यादा dominant है, तो performance gain हो सकता है। शायद काफी सारी serverless function-type scripts इसी category में आती होंगी
  • इससे user-provided JavaScript code चलाया जा सकेगा। मैं user के TypeScript code को sandbox environment में bundler से bundle करने का तरीका ढूंढ रहा था
    QuickJS के अंदर webpack जैसे bundler चलाने के तरीके पर कोई recommendation है?

    • QJS में कैसे करना है, नहीं पता, लेकिन अगर browser में bundler चलाना चाहते हैं तो WebContainers शायद इसी काम के लिए बने हैं
      [1]: https://webcontainers.io/
  • बहुत शानदार। अगर यह WASM में compile हुआ है, तो सोच रहा हूं कि क्या इसे browser में run किया जा सकता है। अगर हो सके, और fetch requests बिना cookies attach किए की जा सकें, तो यह दिलचस्प होगा

  • पिछली नौकरी में Quickjs-emscripten में इतने ज्यादा segmentation fault और silent errors आए कि project hold पर चला गया
    अगर फिर से करना पड़े, तो शायद ऐसा engine चुनूंगा जो ज्यादा programs के साथ ठीक से चलता हो और जिसकी officially approved WASM bundle हो

  • मुझे लगता था कि iframe से code को safely sandbox किया जा सकता है, लेकिन पक्का नहीं हूं। बेशक, अपना interpreter इस्तेमाल करने पर ज्यादा granular time limits, custom APIs जैसी चीजें और भी जोड़ी जा सकती हैं

    • मैं भी इस बारे में और जानना चाहूंगा, खासकर जब इसमें service worker भी मिला हो
      अभी मैं ऐसा iframe इस्तेमाल कर रहा हूं जो window message से code लेता है, input code evaluate करता है और window message से response वापस भेज सकता है, इसलिए यह काफी ठीक काम करता है। हालांकि sandbox से बाहर निकलने का कोई loophole है या नहीं, इस पर भरोसा नहीं है
      ज्यादा complex cases में, जैसे package dependencies, मैंने Babel से parse करके CDN(esm.sh) का इस्तेमाल करने वाला import map बनाने की कोशिश की थी, लेकिन CDN वाला version कभी-कभी सही से काम नहीं करता था
      इसलिए मैंने StackBlitz इस्तेमाल किया, और वह काफी ठीक काम करता है, लेकिन non-secure context वाले environments में कुछ problems हैं
      आखिर में मैंने एक छोटा web server बनाया जो code और dependencies(package.json) लेता है, Docker container के अंदर Vite build चलाता है और result वापस करता है। यह अपने हिसाब से ठीक काम करता है, लेकिन कभी-कभी slow है
      पूरी तरह client-side build कर पाना अच्छा होगा, और StackBlitz मोटे तौर पर यही काम कर रहा है
    • iframe को बहुत ज्यादा permissions मिलती हैं। उदाहरण के लिए, iframe data को third party तक exfiltrate कर सकता है