__proto__ ইনজেকশন কী
সংক্ষেপে: `JSON.parse` `__proto__`-কে সাধারণ কি ধরে; ক্ষতি হয় রিকার্সিভ মার্জে যা `Object.prototype`-এ লেখে, ফলে প্রতিটি অবজেক্ট আক্রমণকারীর প্রপার্টি উত্তরাধিকার পায়।

মূল কথা: যেকোনো মার্জের আগে __proto__, constructor ও prototype আটকান, অবিশ্বস্ত ইনপুট Object.create(null)-এ মার্জ করুন, আর CI-তে একটি প্রোটোটাইপ দাবি যোগ করুন; কেবল লাইব্রেরি patched করাই যথেষ্ট নয়।
এক বাক্যে: __proto__ নামের অবিশ্বস্ত কি রিকার্সিভ মার্জের সঙ্গে মেলে, আর মার্জ প্রোটোটাইপে লেখে।
পুনরুৎপাদন
function merge(target, source) {
for (const key in source) {
if (typeof source[key] === 'object' && source[key] !== null) {
target[key] = target[key] || {};
merge(target[key], source[key]);
} else {
target[key] = source[key];
}
}
return target;
}
merge({}, JSON.parse('{"__proto__": {"isAdmin": true}}'));
console.log({}.isAdmin); // true
কোনো ব্যবসায়িক অবজেক্ট ছোঁয়া হয়নি। Object.prototype ছোঁয়া হয়েছে, আর এখন প্রতিটি অবজেক্টে isAdmin।
JSON.parse দোষী নয় কেন
const data = JSON.parse('{"__proto__": {"a": 1}}');
Object.getOwnPropertyNames(data); // [ '__proto__' ]
Object.getPrototypeOf(data) === Object.prototype; // true, untouched
__proto__ সাধারণ নিজস্ব প্রপার্টি হিসেবে আসে। বিপদ পুরোটাই পরে মার্জ, deep-copy বা পাথ দিয়ে সেট করা কোডে — _.merge, কিছু Object.assign প্যাটার্ন, আর অগণিত হাতে লেখা set(obj, path, value) হেল্পার।
প্রভাব
- অনুমোদন বাইপাস:
if (user.isAdmin)অনিবার্যভাবে সত্য হয় - ডেটা বিকৃতি: অপ্রত্যাশিত ফিল্ড সংরক্ষিত রেকর্ডে সিরিয়ালাইজ হয়
- ডিনায়াল অফ সার্ভিস: প্রোটোটাইপে জোড়া বড় অবজেক্ট স্থায়ীভাবে মেমরি বাড়ায়
- উত্তরণ: টেমপ্লেট ইঞ্জিন বা কমান্ড রানারের সঙ্গে মিলে রিমোট কোড এক্সিকিউশন ঘটিয়েছে
চার প্রতিরক্ষা
কি ফিল্টার করুন।
const FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
কেবল __proto__ আটকানো যথেষ্ট নয়: constructor.prototype একই জায়গায় পৌঁছায়।
নাল-প্রোটোটাইপ অবজেক্টে মার্জ করুন।
const safeTarget = Object.create(null);
প্রোটোটাইপ চেইন না থাকায় __proto__ নিছক স্ট্রিং কি।
in-এর বদলে Object.hasOwn ব্যবহার করুন। in প্রোটোটাইপ চেইন দেখে।
নির্ভরতা patched রাখুন। lodash, deepmerge ও json-patch — সবই এই শ্রেণির বাগের সমাধান প্রকাশ করেছে। npm audit দেখুন।
ঠিক থেকেছে কি না যাচাই
__proto__ ও constructor ধারণকারী পেললোড আপনার মার্জের মধ্য দিয়ে চালান, তারপর দাবি করুন:
console.log({}.polluted); // undefined
console.log(Object.prototype.polluted); // undefined
CI-তে একটি দাবি, প্রায় শূন্য খরচ, পরের রিফ্যাক্টর থেকে রিগ্রেশন ধরে।
সাধারণ প্রশ্ন
মার্জে কোন কি ফিল্টার করা উচিত?
__proto__, constructor ও prototype একসঙ্গে আটকান। কেবল __proto__ ফিল্টার যথেষ্ট নয়, কারণ constructor.prototype একই প্রোটোটাইপে পৌঁছায়।
Object.create(null) লেখা আটকায় কেন?
নাল-প্রোটোটাইপ অবজেক্টে প্রোটোটাইপ চেইন নেই, তাই __proto__ সাধারণ স্ট্রিং কি থাকে। এটি ডেটা কন্টেইনার হিসেবে কাজ করে, কিন্তু কি-ফিল্টারিং বা নির্ভরতা হালনাগাদ প্রতিস্থাপন করে না।
CI-তে প্রোটোটাইপ দূষণ কীভাবে পরীক্ষা করব?
__proto__ ও constructor ধারণকারী পেললোড মার্জের মধ্য দিয়ে পাঠিয়ে দাবি করুন {}.polluted ও Object.prototype.polluted — দুটোই undefined। একটি দাবি প্রায় কিছুই খরচ করে না আর পরের রিফ্যাক্টর থেকে রিগ্রেশন ধরে।