ایک لرننگ پلیٹ فارم جو طلباء کو MongoDB queries لکھنے کی اجازت دیتا ہے، اس نے Node.js کا vm ماڈیول ختم کر دیا ہے اور اب وہ ہر کوئری کو چلانے سے پہلے ایک abstract syntax tree (AST) میں تبدیل (parse) کرتا ہے۔ یہ تبدیلی اس sandbox کو ختم کرتی ہے جسے توڑا جا سکتا تھا، جس سے بیک اینڈ کو اس طرح کے کسی بھی کوڈ (arbitrary code) سے تحفظ ملتا ہے جو ایک غلط طریقے سے بنائی گئی اسٹرنگ (malformed string) کے ذریعے داخل کیا جا سکتا ہے۔

اصل sandbox کیوں ناکام ہوا

ابتدائی عمل میں ایک لائیو ڈیٹا بیس ہینڈل کو vm.runInContext کال میں لپیٹا گیا تھا اور ریگولر ایکسپریشن (regular expression) کے ذریعے صارفین کو محدود کرنے کی کوشش کی گئی تھی۔ یہ صرف find یا aggregate جیسے میتھڈ کے ناموں کی اجازت دیتا تھا؛ باقی تمام آئیڈینٹیفائرز (identifiers) کو فلٹر کر دیا جانا تھا۔

دو خامیوں نے اس طریقے کو غیر محفوظ بنا دیا:

  • Regex فلٹرنگ کو بائی پاس کیا جا سکتا ہے۔ JavaScript کوڈ کو براکٹ نوٹیشن (obj["constructor"]) استعمال کرنے کی اجازت دیتا ہے تاکہ کسی بھی پراپرٹی تک پہنچا جا سکے۔ ایک حملہ آور Function کنسٹرکٹر حاصل کر سکتا ہے، ایک نیا فنکشن بنا سکتا ہے، اور اپنی مرضی کا کوئی بھی کوڈ چلا سکتا ہے۔ ریگکس (regex) اصل پراپرٹی تک رسائی کو کبھی نہیں دیکھ پاتا کیونکہ سورس کو ان گنت طریقوں سے دوبارہ لکھا جا سکتا ہے۔
  • vm کوئی سیکیورٹی باؤنڈری نہیں ہے۔ Node کی دستاویزات کے مطابق vm صرف global آبجیکٹ کو الگ (isolate) کرتا ہے، پورے پروسیس کو نہیں۔ سینڈ باکس میں ایک لائیو ڈیٹا بیس کنکشن شامل کرنے سے، اس سیاق و سباق (context) کے اندر موجود کوڈ اس کنکشن پر کسی بھی میتھڈ کو کال کرنے کی صلاحیت برقرار رکھتا تھا، بشمول وہ میتھڈ جو ڈیٹا لکھتے یا ڈیلیٹ کرتے ہیں۔ سینڈ باکس نے کوڈ کو ہوسٹ پروسیس (host process) کو متاثر کرنے سے نہیں روکا۔

AST پر مبنی حل

ٹیم نے کوڈ کے ایگزیکیوشن کو اسٹیٹک اینالیسس (static analysis) سے بدل دیا۔ کوئری اسٹرنگز اب acorn پارسر کو بھیجی جاتی ہیں، جو ایک AST تیار کرتا ہے—جو کوڈ کے سنٹیکٹک ڈھانچے کی ایک درخت نما (tree) نمائندگی ہے۔ AST کا ایک سخت وائٹ لسٹ (whitelist) کے خلاف نوڈ بہ نوڈ معائنہ کیا جاتا ہے:

  • Literals، arrays اور objects کی اجازت صرف تب ہوتی ہے جب وہ سادہ ویلیوز کے طور پر ظاہر ہوں۔
  • Method calls کو ایک پہلے سے طے شدہ سیٹ (find, sort, limit, وغیرہ) تک محدود رکھا گیا ہے۔ کوئی بھی دوسری کال مسترد کر دی جاتی ہے۔
  • Computed property access (مثلاً obj[expr]) یا کوئی بھی ایسا نوڈ ٹائپ جو واضح طور پر فہرست میں نہ ہو، فوری طور پر ناکامی کا سبب بنتا ہے۔

چونکہ پارسر درخت (tree) پر کام کرتا ہے، نہ کہ خام متن (raw text) پر، اس لیے اسے متبادل ہجے (spellings) یا براکٹ نوٹیشن کی چالوں سے دھوکہ نہیں دیا جا سکتا۔ ایک کنسٹرکٹر چین جو ریگکس سے بچ نکل سکتی تھی، ایک غیر شناخت شدہ نوڈ کے طور پر ظاہر ہوتی ہے اور کوڈ چلنے سے پہلے ہی مسترد کر دی جاتی ہے۔

سیکیورٹی کے لیے اس کا کیا مطلب ہے

نیا ڈیزائن "deny by default" (بذریعہ ڈیفالٹ انکار) کے فلسفے پر عمل کرتا ہے:

  • یہ طے کریں کہ کیا جائز ہے، نہ کہ یہ کہ کیا ممنوع ہے۔ ٹیکسٹ پر مبنی allow-listing مکمل نہیں ہو سکتی؛ لیکن ایک AST میں نوڈ ٹائپس کا ایک محدود سیٹ ہوتا ہے، جس سے مکمل چیکنگ ممکن ہو جاتی ہے۔
  • سینڈ باکس کے اندر کبھی بھی لائیو ریسورسز کو ظاہر نہ کریں۔ ایک الگ سیاق و سباق (isolated context) میں ڈیٹا بیس ہینڈل بھیجنے سے سینڈ باکسڈ کوڈ کو بیک اینڈ تک براہ راست رسائی مل جاتی ہے۔ پارسر کا طریقہ کار صارف کے کوڈ کو کبھی بھی لائیو آبجیکٹ نہیں دیتا؛ یہ صرف کوئری کے مقصد (intent) کو نکالتا ہے۔
  • ڈھانچے کی تصدیق کریں، پھر محفوظ طریقے سے چلائیں۔ ایک بار جب AST تصدیق (validation) مکمل کر لیتا ہے، تو پلیٹ فارم اپنے قابل اعتماد کوڈ پاتھ کا استعمال کرتے ہوئے اجازت یافتہ کالز کو اصل MongoDB driver میتھڈز میں تبدیل کر دیتا ہے۔

آگے کیا دیکھنا ہے

  • اپنے کوڈ بیس میں eval, new Function, یا vm کے کسی بھی استعمال کا آڈٹ کریں۔ یہاں تک کہ وائٹ لسٹ کو بھی JavaScript کی متحرک (dynamic) نوعیت کے ذریعے نقصان پہنچایا جا سکتا ہے۔
  • جہاں بھی ممکن ہو، صارف کے تیار کردہ کوڈ کے لیے AST parsing اپنائیں۔ acorn, esprima, یا babel-parser جیسی لائبریریاں اس تبدیلی کو آسان بنا دیتی ہیں۔
  • لائیو آبجیکٹس کے پھیلاؤ کو محدود کریں۔ اگر ڈیٹا بیس کنکشن، فائل ہینڈل، یا نیٹ ورک ساکٹ تک رسائی ضروری ہے، تو اسے ایک پراکسی (proxy) میں لپیٹ دیں جو صرف ان کم سے کم میتھڈز کو ظاہر کرے جن کی آپ اجازت دینا چاہتے ہیں۔
  • ایج کیسز (edge cases) کی ٹیسٹنگ کو خودکار بنائیں۔ ایسی کوئریز تیار کریں جو براکٹ نوٹیشن، کمپیوٹڈ کیز (computed keys)، یا پروٹو ٹائپ مینیپولیشن (prototype manipulation) کا استعمال کرتی ہوں تاکہ یہ تصدیق کی جا سکے کہ آپ کا پارسر انہیں مسترد کر دیتا ہے۔

خلاصہ

سینڈ باکس کے طور پر vm.runInContext پر بھروسہ کرنا سیکیورٹی کا ایک غلط احساس دیتا ہے؛ ریگکس فلٹرز JavaScript کی لچکدار سنٹیکس کو کور نہیں کر سکتے، اور سینڈ باکس پروسیس ریسورسز کو الگ نہیں کرتا۔ صارف کے ان پٹ کو AST میں تبدیل کرنا اور صرف ان نوڈز کو وائٹ لسٹ کرنا جنہیں آپ سمجھتے ہیں، ایک ٹھوس اور برقرار رکھنے کے قابل رکاوٹ فراہم کرتا ہے جو بدنیتی پر مبنی کوڈ کو چلنے سے پہلے ہی روک دیتا ہے۔ اگر آپ کا پلیٹ فارم صارفین کو کوڈ لکھنے کی اجازت دیتا ہے، تو آج ہی eval-اسٹائل کے ایگزیکیوشن کو اسٹیٹک اینالیسس سے بدل دیں۔