蓝桥杯-网络安全比赛(5)基础学习-JavaScript原型链的prototype、constructor、object.create()、__proto__

JavaScript的prototype、constructor、Object.create()和__proto__通常不直接作为解题的关键,但它们对于理解和分析Web应用的安全性至关重要。
网络安全比赛通常涉及Web应用的漏洞挖掘和攻击,这要求参赛者具备深厚的Web开发知识,包括JavaScript的原型链和继承机制。
  1. 原型链污染 :参赛者可能需要了解prototype__proto__以识别和利用原型链污染漏洞。
    攻击者可能通过修改对象的原型来影响所有继承自该原型的对象,从而执行恶意代码或绕过安全限制。
  2. 对象操作和属性访问 :在网络安全比赛中,参赛者经常需要分析JavaScript对象的结构和属性。
    了解prototypeconstructor可以帮助他们更好地理解对象的来源和行为,从而找到潜在的漏洞。
  3. 代码审计 :参赛者在审计Web应用的源代码时,可能会遇到使用Object.create()创建对象的代码。
    了解这种方法可以帮助他们理解对象的创建过程和属性继承,从而发现潜在的安全问题。
  4. 绕过安全限制 :在某些情况下,攻击者可能会尝试利用JavaScript的原型链和继承机制 来绕过浏览器的安全限制或Web应用的安全机制。
    了解这些概念可以帮助参赛者识别和防御这类攻击。

原型链

JavaScript的原型链机制是JavaScript对象继承属性或方法的主要方式。
每个JavaScript对象(除了null)都有一个指向它的原型(prototype)对象的内部链接。
这个原型对象自身也可以有原型,这样一层一层地链接下去,就构成了原型链。

prototype

每个函数都有一个 prototype 属性,它是一个对象,用于存储可以由特定类型的所有实例共享的属性和方法。

当尝试访问一个对象的属性时,如果该对象自身没有这个属性,那么 JavaScript 引擎会在该对象的 __proto__(即其原型)上查找这个属性,这个过程会一直持续到找到属性或者到达原型链的末端(通常是 null)。

javascript 复制代码
function Person(name) {  
  this.name = name;  
}  
  
Person.prototype.greet = function() {  
  console.log(`Hello, ${this.name}!`);  
};  
  
const alice = new Person('Alice');  
const bob = new Person('Bob');  
  
Person.prototype.age = 30; // 所有实例的 age 属性都是 30  
  
console.log(alice.age); // 输出: 30  
console.log(bob.age); // 输出: 30
alice.greet(); // 输出: Hello, Alice!

谨慎扩展内置对象的原型:修改内置对象的原型(如 Object、Array

等)可能会导致不可预见的副作用,因为其他代码可能也依赖于这些内置对象的行为。

constructor

每个对象都有一个 constructor 属性,它指向创建该对象实例的构造函数。

通常,当我们修改 prototype 时,需要确保 constructor 指向正确的构造函数,以避免混淆。

案例:

javascript 复制代码
function Person(name) {  
  this.name = name;  
}  
  
Person.prototype.greet = function() {  
  console.log(`Hello, ${this.name}!`);  
};  
// 忘记设置 constructor,可能导致问题  
const alice = new Person('Alice');  
console.log(alice.constructor === Person); // 输出: false,应该是 true  
  
// 确保 constructor 指向正确的构造函数  
Person.prototype.constructor = Person;  
console.log(alice.constructor === Person); // 输出: true

Object.create()

Object.create() 方法创建一个新对象,使用现有的对象来提供新创建的对象的 __proto__

案例:

javascript 复制代码
const personProto = {  
  greet: function() {  
    console.log(`Hello, ${this.name}!`);  
  }  
};  

const bob = Object.create(null); // 没有原型链  
bob.greet(); // 报错:bob.greet is not a function
  
const alice = Object.create(personProto);  
alice.name = 'Alice';  
alice.greet(); // 输出: Hello, Alice!

proto

__proto__ 是一个内部属性(在大多数现代浏览器中是可访问的),它指向对象的原型。(通常不会直接操作 __proto__,而是使用 Object.create() 或构造函数来设置对象的原型。)

案例:

javascript 复制代码
function Person(name) {  
  this.name = name;  
}  
  
const alice = new Person('Alice');  
  
console.log(alice.__proto__ === Person.prototype); // 输出: true

不要直接修改 prototype __proto__:尽量通过添加属性或方法到原型对象来扩展对象的功能,而不是直接修改原型对象本身。

更好的做法是使用 Object.definePropertyObject.assign 等方法来扩展对象,而不是直接修改 __proto__

例题

题目1

创建一个 Animal 构造函数,它有一个 speak 方法。
然后创建一个 Dog 构造函数,它继承自 Animal 构造函数,并有一个 bark 方法。
最后,创建一个 Dog 的实例并调用它的 speak 和 bark 方法。

解答:

javascript 复制代码
function Animal() {}  
  
Animal.prototype.speak = function() {  
  console.log('The animal speaks.');  
};  
  
function Dog() {}  
  
// Dog 继承自 Animal  
Dog.prototype = Object.create(Animal.prototype);  
Dog.prototype.constructor = Dog;  
  
Dog.prototype.bark = function() {  
  console.log('The dog barks.');  
};  
  
const myDog = new Dog();  
myDog.speak(); // 输出: The animal speaks.  
myDog.bark(); // 输出: The dog barks.

题目2

创建一个Vehicle基类,它有一个move方法。
接着创建两个派生类Car和Bicycle,它们继承自Vehicle类,
并且各自添加了自己的特性方法(Car有honk方法,Bicycle有pedal方法)。
最后,创建这两个派生类的实例,并调用它们的方法。

要求:

  1. 使用原型链来实现继承。
  2. 确保每个对象的constructor属性指向正确的构造函数。
  3. 使用Object.create()来设置原型。

解答:

javascript 复制代码
// 1. 创建 Vehicle 基类  
function Vehicle() {  
  // 构造函数内容(如果有的话)  
}  
  
Vehicle.prototype.move = function() {  
  console.log('The vehicle is moving.');  
};  
  
// 2. 创建 Car 类,继承自 Vehicle  
function Car() {}  
  
// 使用 Object.create() 设置原型  
Car.prototype = Object.create(Vehicle.prototype);  
Car.prototype.constructor = Car; // 确保 constructor 指向正确的构造函数  
  
Car.prototype.honk = function() {  
  console.log('The car honks.');  
};  
  
// 3. 创建 Bicycle 类,继承自 Vehicle  
function Bicycle() { }  
  
// 使用 Object.create() 设置原型  
Bicycle.prototype = Object.create(Vehicle.prototype);  
Bicycle.prototype.constructor = Bicycle; // 确保 constructor 指向正确的构造函数  
  
Bicycle.prototype.pedal = function() {  
  console.log('The bicycle is being pedaled.');  
};  
  
// 4. 创建实例并调用方法  
const myCar = new Car();  
myCar.move(); // 输出: The vehicle is moving.  
myCar.honk(); // 输出: The car honks.  
  
const myBicycle = new Bicycle();  
myBicycle.move(); // 输出: The vehicle is moving.  
myBicycle.pedal(); // 输出: The bicycle is being pedaled.  
  
// 5. 验证原型链和 constructor  
console.log(myCar.__proto__ === Car.prototype); // 输出: true  
console.log(myCar.__proto__.__proto__ === Vehicle.prototype); // 输出: true  
console.log(myCar.constructor === Car); // 输出: true  
  
console.log(myBicycle.__proto__ === Bicycle.prototype); // 输出: true  
console.log(myBicycle.__proto__.__proto__ === Vehicle.prototype); // 输出: true  
console.log(myBicycle.constructor === Bicycle); // 输出: true

总结

通过今天的学习,你应该能够更好地理解JavaScript的原型链和继承机制,并能够在实际开发中灵活运用这些概念。

同时,你也应该意识到这些概念在Web应用安全性分析中的重要性,这对于参与网络安全比赛或从事Web安全相关工作的人来说是非常有价值的。

系列文章

蓝桥杯-网络安全比赛(4)基础学习-JavaScript同步与异步、宏任务与微任务
蓝桥杯-网络安全比赛(3)基础学习- JavaScript的闭包与this
蓝桥杯-网络安全比赛(2)基础学习-正则表达式匹配
蓝桥杯-网络安全比赛(1)基础学习-使用PHP、PYTHON、JAVA

相关推荐
nameofworld14 分钟前
前端面试笔试(二)
前端·javascript·面试·学习方法·数组去重
程序员劝退师_25 分钟前
Kafka学习笔记
笔记·学习·kafka
帅比九日34 分钟前
【HarmonyOS NEXT】实战——登录页面
前端·学习·华为·harmonyos
李笠^_^41 分钟前
Python学习------第八天
学习
Lotay_天天1 小时前
删库跑路,启动!
学习
爱吃生蚝的于勒1 小时前
C语言最简单的扫雷实现(解析加原码)
c语言·开发语言·学习·计算机网络·算法·游戏程序·关卡设计
hummhumm1 小时前
第 12 章 - Go语言 方法
java·开发语言·javascript·后端·python·sql·golang
hummhumm1 小时前
第 8 章 - Go语言 数组与切片
java·开发语言·javascript·python·sql·golang·database
麻花20131 小时前
WPF学习之路,控件的只读、是否可以、是否可见属性控制
服务器·前端·学习
wywcool1 小时前
JVM学习之路(5)垃圾回收
java·jvm·后端·学习