蓝桥杯-网络安全比赛(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

相关推荐
秋雨凉人心1 小时前
简单发布一个npm包
前端·javascript·webpack·npm·node.js
B1nna2 小时前
Redis学习(三)缓存
redis·学习·缓存
_im.m.z2 小时前
【设计模式学习笔记】1. 设计模式概述
笔记·学习·设计模式
哥谭居民00013 小时前
将一个组件的propName属性与父组件中的variable变量进行双向绑定的vue3(组件传值)
javascript·vue.js·typescript·npm·node.js·css3
踢足球的,程序猿3 小时前
Android native+html5的混合开发
javascript
前端没钱3 小时前
探索 ES6 基础:开启 JavaScript 新篇章
前端·javascript·es6
黑客Ela5 小时前
【网络安全设备系列】7、流量监控设备
安全·web安全
左漫在成长5 小时前
王佩丰24节Excel学习笔记——第十九讲:Indirect函数
笔记·学习·excel
一条不想当淡水鱼的咸鱼5 小时前
taro中实现带有途径点的路径规划
javascript·react.js·taro
土豆炒马铃薯。5 小时前
【Vue】前端使用node.js对数据库直接进行CRUD操作
前端·javascript·vue.js·node.js·html5