If you're trying to figure out what how to achieve prototype chain contamination in JavaScript, then you first need to figure out two things, and those are__proto__
cap (a poem)prototype
。
What exactly is__proto__
cap (a poem)prototype
?
So let's take a look at the more official story first:
__proto___: is a hidden property of every object that points to the prototype of the constructor that created it. It is the mechanism used by objects to inherit properties and methods. It is an object. All objects can access its prototype through __proto___, which in turn enables prototype chain lookup.
A prototype is an attribute specific to a function (especially a constructor) that is used to define properties and methods shared by instances created by that constructor. prototype is often used to define the instance methods of a constructor. When we create a new object, the object inherits the properties and methods from its constructor prototype.
const obj = {};
(obj.__proto__ === ); // true
In this example, theobj
attributableObject
constructor is created, so theobj.__proto__
directional。
Then we can understand this way, prototype is a property of the class, when the class is instantiated into an object, the object will have the properties and methods in the prototype. When an object wants to access the prototype of a class, it uses the__proto__
attribute to access the class prototype.
prototype chain
realize__proto__
cap (a poem)prototype
After that, then we're going to dive into JavaScript's inheritance chain, where every object has an internal link to its prototype (the__proto__
), this prototype is itself an object, and usually has its own prototype, thus forming a chain of prototypes. When you access a property of an object, JavaScript looks up this chain of prototypes until it finds the property or the top of the chain (i.e.).
function Animal(name) {
= name;
}
function Something() {
= ( + ' makes a beautiful sound.');
};
const dog = new Animal('Dog');
; // exports: 'Dog makes a beautiful sound.'
Instantiating the Animal class creates the dog object, and when accessing the speak attribute, when it is not found in dog, it is found in thedog.__proto__.__proto__
Look in and finddog.__proto__.__proto__
There is a speak attribute in theThere is a speak attribute in the This means that JavaScript uses prototype chains to implement the inheritance mechanism.
Prototype Chain Pollution (Prototype Chain Pollution)
So aren't we learning about inheritance, prototype chaining, in order to do chain contamination and get what we want?
this being the casedog.__proto__.__proto__
points to the prototype object of the constructor that created the object (). Then we modify the
dog.__proto__.__proto__
The content of the class is not something that can be implemented in turn to modify the Something class.
Example:
function Animal(name) {
= name;
}
function Something() {
= ( + ' makes a beautiful sound.');
};
const dog = new Animal('Dog');
dog.__proto__.speak = ('Modified successfully');
;
With this result we can see that we easily put thedog.__proto__.__proto__
of the speak value was changed. Let's get this inheritance chain out of the way:
dog -> -> -> -> null
Then an attacker who controls and modifies the prototype of an object through an entry point will potentially affect all objects from the same class, parent class up to the Object class as this object.
Typically, merge operations lead to contamination of the prototype chain:
javascript
function merge(target, source) {
for (let key in source) {
if (key in source && key in target) {
merge(target[key], source[key])
} else {
target[key] = source[key]
}
}
}
let object1 = {}
let object2 = ('{"a": 1, "__proto__": {"b": 2}}')
merge(object1, object2)
(, )
object3 = {}
()
//1 2
//2
In the case of JSON parsing, the__proto__
is considered a real "key name", not a "prototype", so it will be present when traversing object2.