原型和原型链

对象

在 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 引擎会执行以下查找过程:

  1. 首先,在对象自身的属性中查找。如果找到,就直接使用。
  2. 如果没有找到,引擎会顺着对象的 __proto__ 属性,去它的原型对象中查找。
  3. 如果原型对象中依然没有,就继续去原型的原型中查找。
  4. 以此类推,顺藤摸瓜,直到找到该属性,或者到达原型链的顶端(Object.prototype.__proto__,它的值是 null)。
  5. 如果到了 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到一个空对象中)