O
First of all, it is worth minimising what JavaScript prototypes are. Basically, every JavaScript object can inherit properties and methods from https://pt.stackoverflow.com/a/15247/69296 .Primitives, in turn, are not objects and therefore have no properties, but in the face of something called " https://developer.mozilla.org/pt-BR/docs/Glossario/Primitivo#Wrappers_em_JavaScript ", have associations with the corresponding objects. For example, the primitive string is involved by the builder String; primitive number, by Number and so on. That is why, although primitives do not have properties, you can, in practice, access properties in "principle values".Modifying __proto__Prototype pollution (prototype pollution), in short, it happens when you modify the prototype of a value, which will reflect on the change of all other values that share the same prototype. Here's an example:const obj1 = { name: 'Foo' };
const obj2 = { name: 'Bar' };
console.log(obj1.changed); // undefined
console.log(obj2.changed); // undefined
obj1.proto.changed = true;
console.log(obj1.changed); // true
console.log(obj2.changed); // true
const obj3 = { name: 'Baz' };
const str1 = 'Qux';
console.log(obj3.changed); // true
console.log(str1.changed); // trueIn the example above, I used the property proto (present in all objects) to access and change the prototype of a given object. Currently, language also offers other mechanisms to do this, as Reflect.getPrototypeOf and Reflect.setPrototypeOf. By virtue of the fact that proto being present in all language objects, it becomes trivial to change (often unintentionally) the prototype of a certain object.Note that when changing the object proto, you change is changing the prototype of the object that contains it. In the above example, we are modifying the object Object.prototype (which is the prototype of the literal object we created).Also note that, as prototypes form a chain, when modifying Object.prototype, virtually all JavaScript values will also have been invaded since virtually everything extends Object (except null and undefined). This is because, unlike primitives, in JavaScript, objects are passed by Reference. Thus, as the prototype of a given object is often shared (by reference) among several other objects ("instances"), you will probably change something that was not to be modified, since the changes in this case, are not local, but rather global among all the values that share that reference.This vulnerability is very common in fusion operations (merge), cloning (clone), assignment via path (path assignment) or extension (extend) of objects.Note that, <obj>.proto allows direct access to the property prototype of the constructor of a given object. You can also access it (and modify it) via <obj>.constructor.prototype. Learn more about the property https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Object/Constructor Here. To appear, unlike proto, the property construtor http://ecma-international.org/ecma-262/11.0/index.html#sec-object.prototype.constructor .If you are working with objects dynamically, you should then ensure that you modify the property proto or constructor by mistake, which can be used as a means for this type of attack. You can also use the method https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Object/HasOwnProperty to ensure that you are not using property inherited from the prototype chain.It is far from a good solution to the problem, but it is interesting to comment that there is how to disable or prevent the use of proto Node. js through flag https://nodejs.org/api/cli.html#cli_disable_proto_mode .Extension of native objects (constructor augmentation)Another very common form prototype pollution is to modify the property prototype of a builder. In this case can also be called prototype augmentation, since it is intentional.For example, JavaScript does not have the method Array.prototype.shuffle (to scramble an array). With this, instead of creating a function shuffle, attached one new and non-standardized method in the prototype itself of the arrays. So:Object.defineProperty(Array.prototype, 'shuffle', {
writable: true,
configurable: true,
enumerable: false,
value: function() {
// Implementação qualquer.
console.log('Chamado Array.prototype.shuffle em:', this);
}
});
[1, 2, 3].shuffle();At first, this may seem like a good idea, since it becomes syntically more pleasant. It is much more beautiful to do [1, 2, 3].shuffle than shuffle([1, 2, 3]) — at least a lot of people seem to find. However, this can bring a number of negative consequences:Possible interference between codesIn the case of this practice, nothing guarantees that a library You can extend or modify what a B library has already modified.Long-term compatibility breakIf many people decide to extend a native object, two bad situations may emerge:The specification standardizes the new method and all the code that has modified will be with the unofficial implementation, which is undoubtedly less performing.The specification simply cannot be able to create a new method. That happened to the Array.prototype.contains (original name which, not to break compatibility, had to be changed to Array.prototype.includes). https://github.com/tc39/proposal-Array.prototype.includes#status Change the result of for..inMany people use for..in to iterate on the properties of a certain object. As this loop also takes into account the properties inherited by the prototype (non-own property), if the person does not take the minimum care when extending it, it may affect the links for..in. See:const arr = ['a', 'b'];
// Antes de estender Array.prototype:
for (const key in arr) {
console.log(key, '->', arr[key]);
}
console.log('----');
// Estendendo o protótipo de Array (forma leviana):
Array.prototype.shuffle = function() {
// Implementação qualquer.
console.log('Chamado Array.prototype.shuffle em:', this);
}
// Depois da extensão.
for (const key in arr) {
console.log(key, '->', arr[key]);
}Because of this, in the case of extending a native JavaScript object, it is recommended to use the method Object.defineProperty to create the new property with the attribute [[Enumerable]] defined as false, aiming at not changing the standard behavior of for..in. https://pt.stackoverflow.com/a/478412/69296 In short, only modify the code if you are sure what you are doing. On a small scale, the problem will not be so alarming, but under these conditions it is worth questioning: is it really worth it? Most often a function is enough.