flawopen.com/कमज़ोरियाँ/JavaScript प्रोटोटाइप प्रदूषण
JavaScript प्रोटोटाइप प्रदूषण
ऐसी कार्यशाला सोचें जहाँ हर नया उपकरण अपने सेटिंग्स में उत्तर न मिलने पर साझा नियम-पुस्तिका देखता है। यदि कोई कर्मचारी हमलावर के नियंत्रण वाला नियम उसमें लिख दे, तो दूसरे उपकरण उसे default मान सकते हैं। Prototype pollution में असुरक्षित dynamic property writes किसी object का prototype बदल सकते हैं, कभी-कभी Object.prototype भी। असर अपने-आप global नहीं होता; बाद का application code inherited property पर भरोसा करे तभी प्रभाव पड़ता है।
__proto__ जैसी untrusted keys, या असुरक्षित write तक पहुँचने वाला constructor.prototype pathMap या बिना prototype वाले dictionary का उपयोग करेंमुख्य अवधारणाएँ और उपतंत्र शब्द
- Object.prototype
- साझा prototype जिसे सामान्य objects inherit करते हैं। इसका pollution कई objects को प्रभावित कर सकता है, लेकिन हर JavaScript object या हर realm को नहीं।
- __proto__
- सामान्य objects का पुराना accessor जो उनका prototype पढ़ता या सेट करता है। JSON text में यही spelling पहले साधारण property name है, जब तक बाद का code इसे असुरक्षित ढंग से न संभाले।
- पुनरावर्ती डीप मर्ज
- यह nested keys को पढ़कर दूसरे object में लिखने वाला copier है। Untrusted keys यदि prototype-संबंधित properties या unsafe paths चुन सकें तो यह जोखिमपूर्ण है।
- CWE-1321
- Object prototype attributes में अपर्याप्त रूप से नियंत्रित बदलाव। कमजोरी अनियंत्रित mutation है; आगे का असर reachable application behavior पर निर्भर करता है।
हमले का चरण-दर-चरण प्रवाह
अविश्वसनीय property input
Endpoint हमलावर-नियंत्रित object keys स्वीकार करता है। अपना __proto__ property वाला JSON parse करना अकेले prototype नहीं बदलता।
असुरक्षित dynamic write
Recursive merge या path setter उन keys का अनुसरण करके हर path segment जाँचे बिना dynamic writes करता है।
लक्ष्य या साझा prototype में बदलाव
Target और write sequence के आधार पर operation target का prototype बदल सकता है या Object.prototype जैसे shared prototype तक पहुँच सकता है। ये अलग परिणाम हैं।
प्रभाव gadget पर निर्भर है
बाद का gadget किसी security-sensitive operation में inherited value पढ़ता है। नतीजा उस gadget पर निर्भर है; authentication bypass या code execution मानकर न चलें।
तंत्र और मूल कारण
JavaScript में property lookup prototype chain का अनुसरण करता है। Vulnerable merge या path setter untrusted keys जैसे __proto__ या constructor.prototype को prototype तक write निर्देशित करने दे सकता है। JSON.parse से बना अपना __proto__ field खुद pollution नहीं है; बाद के code को unsafe assignment से उसकी व्याख्या करनी होगी। Target prototype बदलने से वही target प्रभावित होता है; Object.prototype बदलने से उसे inherit करने वाले सामान्य objects प्रभावित होते हैं। Security impact के लिए कोई अलग gadget उस inherited property का उपयोग करे।
// असुरक्षित: हमलावर-नियंत्रित keys recursive writes तक पहुँचती हैं
function merge(target, source) {
for (const key in source) {
const value = source[key];
if (value && typeof value === 'object') {
if (!target[key]) target[key] = {};
merge(target[key], value);
} else {
target[key] = value;
}
}
return target;
}
// JSON.parse अपना __proto__ data property बनाता है; जोखिम unsafe merge में है।
const input = JSON.parse('{"__proto__": {"isAdmin": true}}');
merge({}, input);
// सुरक्षित: केवल endpoint द्वारा स्वीकार किए गए fields कॉपी करें
const PROFILE_KEYS = new Set(['displayName', 'theme']);
function parseProfile(input) {
if (!input || typeof input !== 'object' || Array.isArray(input)) {
throw new TypeError('profile must be an object');
}
const profile = Object.create(null);
for (const key of Object.keys(input)) {
if (!PROFILE_KEYS.has(key)) continue;
const value = input[key];
if (typeof value !== 'string' || value.length > 80) {
throw new TypeError('invalid profile field');
}
profile[key] = value;
}
return profile;
}
हमले और exploit का क्रम
- 1Input: request में अप्रत्याशित object key, जैसे
{"__proto__": {"admin": true}}, शामिल है। JSON parse करना अकेले prototype नहीं बदलता। - 2Unsafe write: generic merge या path setter allowlist के बिना key को process करता है।
- 3Prototype तक पहुँच: code path के अनुसार write target prototype बदल सकता है या shared prototype तक पहुँच सकता है।
- 4Impact gadget: pollution तभी sensitive decision को प्रभावित करता है जब बाद का code inherited property पर भरोसा करे। वास्तविक gadget और authorization path की जाँच करें।
रक्षात्मक इंजीनियरिंग और रोकथाम नियम
- ✓Schema allowlists को प्राथमिकता दें: केवल endpoint द्वारा स्वीकार किए जाने वाले fields से target बनाएँ। Generic path writer अपरिहार्य हो तो हर स्तर पर prototype-संबंधित path segments अस्वीकार करें।
- ✓सुरक्षित dictionaries इस्तेमाल करें: मनमानी user keys को
MapयाObject.create(null)dictionary में रखें; साधारण objects अपेक्षित करने वाली APIs को देने से पहले validate करें। - ✓Own properties जाँचें: security-sensitive presence checks के लिए
Object.hasOwn(record, key)इस्तेमाल करें; inherited defaults को actions authorize न करने दें। - ✓Runtime hardening को defense in depth मानें: Node.js का
--disable-proto=throwएक रास्ता हटाता है, परconstructor.prototypeनहीं रोकता। Built-ins freeze करने से polyfills और dependencies टूट सकती हैं; compatibility जाँचें और इसे safe writes का विकल्प न मानें।
अक्सर पूछे जाने वाले प्रश्न
नहीं। JSON.parse() __proto__ नाम की own data property बनाता है और inherited setter नहीं चलाता। बाद का merge या assignment setter चलाए तो जोखिम है। देखें क्या JSON.parse() Prototype Pollution करता है?
यह frozen Object.prototype में लिखने से रोक सकता है, लेकिन setter को किसी एक object का prototype बदलने से या अन्य prototypes को प्रभावित करने से नहीं रोकता। Built-ins बढ़ाने वाली libraries भी टूट सकती हैं। इसे केवल defense-in-depth मानें, data-handling fix नहीं।
नहीं। Types runtime पर मिट जाते हैं। Record<string, string> घोषित value में भी __proto__ key हो सकती है। Untrusted keys validate करें और objects सुरक्षित तरीके से बनाएँ।
- MDN — JavaScript प्रोटोटाइप प्रदूषण
- OWASP — प्रोटोटाइप प्रदूषण रोकथाम मार्गदर्शिका
- CWE-1321 — Object prototype attributes में अपर्याप्त रूप से नियंत्रित बदलाव
- MDN — Object.prototype.__proto__ accessor