原型和原型链
对象
在 JavaScript 中,对象是无序属性的集合,其属性可以包含基本值、对象或者函数(方法)。你可以将对象简单地看作是一个包含键值对(Key-Value pairs)的容器。
const user = {
name: "Alice",
age: 25,
greet: function() {
console.log("Hello, I'm " + this.name);
}
};
// 访问对象属性
console.log(user.name); // "Alice"
user.greet(); // "Hello, I'm Alice"
原型
每个 JavaScript 对象(除了 null)在创建时,都会与另一个对象自动关联。这个被关联的对象就被称为原型。对象可以从它的原型上“继承”属性和方法。
原型涉及两个容易混淆的概念:
__proto__(隐式原型):这是每一个对象都有的内部属性(在规范中称为[[Prototype]]),它指向该对象的原型。prototype(显式原型):这是只有函数才拥有的属性。当你使用new关键字通过构造函数创建实例时,实例对象的__proto__会自动指向构造函数的prototype。
// 构造函数
function Person(name) {
this.name = name; // 定义在实例上的属性
}
// 在构造函数的 prototype 对象上添加方法
Person.prototype.sayHello = function() {
console.log("Hi!");
};
const alice = new Person("Alice");
// 实例的隐式原型指向构造函数的显式原型
console.log(alice.__proto__ === Person.prototype); // true
原型链
原型链是 JavaScript 实现继承的底层机制。
当你在一个对象上访问某个属性或方法时,JavaScript 引擎会执行以下查找过程:
- 首先,在对象自身的属性中查找。如果找到,就直接使用。
- 如果没有找到,引擎会顺着对象的
__proto__属性,去它的原型对象中查找。 - 如果原型对象中依然没有,就继续去原型的原型中查找。
- 以此类推,顺藤摸瓜,直到找到该属性,或者到达原型链的顶端(
Object.prototype.__proto__,它的值是null)。 - 如果到了
null还没找到,就返回undefined。
这种由 __proto__ 属性将各个对象串联起来的链式结构,就是原型链。
原型链污染
概念
原型链污染是一种针对javascript运行时的注入攻击。通过原型链污染,攻击者可能控制对象属性的默认值。这允许攻击者篡改应用程序的逻辑,还可能导致拒绝服务,在极端情况下甚至导致远程代码执行
继承关系
原型是继承的基础,JavaScript中原型链可以通过prototype这个属性来实现继承关系
fuction Father(){
this.first_name='Donald'
this.last_name='Trump'
}
fuction Son(){
this.first_name='Melania'
}
Son.prototype=new Father()
let son=new Son()
console.log(`Name:${son.first_name ${son.lat_name}}`)//Name:Melania Trump
原理
fuction Father(){
this.first_name='Donald'
this.last_name='Trump'
}
fuction Son(){
this.first_name='Melania'
}
Son.prototype=new Father()
son.__proto__['last_name']='kawihi';
let son=new Son();
console.log(`son Name:${son.last_name}`);//son Name:kawhi
console.log(`secondson Name:$(secondson.last_name)`); //secondson Name:kawhi
可以发现修改了son的原型属性之后会影响到另一个具有相同原型的对象,不难看出我们是通过设置了__proto__的值来影响原型的属性
实战
在实际应用中,哪些情况下可能会导致原型链能被攻击者修改? 其实找找控制数组(对象)的“键名”的操作即可:
- 对象merge
- 对象clone(其实就是内核将待操作的对象merge到一个空对象中)