js创建对象的三种方法 :

  • 普通创建

var person={name:'lihuaiqiu','age','19'}
​
var person={}  //创建空对象
  • 构造函数方法创建

function person(){this.name="liahuqiu";this.test=function () {return 23333;
​
}
}
person.prototype.a=3;
web=new person();
console.log(web.test());
console.log(web.a)
  • 通过object创建

var a=new Object();
a.c=3
console.log(a.c)

函数即对象(这里的函数有点类似于一个类)

prototype和proto用法

对象.proto=构造器(构造函数).prototype

构造器.prototype其实也是一个对象,为构造函数的原型对象,同样有__proto__属性,一直通过原型链__proto__最终可找到null。

我们可以通过Foo.prototype来访问Foo类的原型,但Foo实例化出来的对象,是不能通过prototype访问原型的。这时候,就该__proto__登场了。

一个Foo类实例化出来的foo对象,可以通过foo.__proto__属性来访问Foo类的原型,也就是说:

foo.__proto__ == Foo.prototype

这里类Foo在实例化时,便可调用prototype中的方法 所以,总结一下:

prototype是一个类的属性,所有类对象在实例化的时候将会拥有prototype中的属性和方法 一个对象(foo)的__proto__属性,指向这个对象所在的类(Foo)的prototype属性

这个特性被用来实现JavaScript中的继承机制

比如:

function Father() {this.first_name = 'Donald'this.last_name = 'Trump'
}function Son() {this.first_name = 'Melania'
}Son.prototype = new Father()//这里Son.prototype意思是Son的父类,let son = new Son()
console.log(`Name: ${son.first_name} ${son.last_name}`)

Son类继承了Father类的last_name属性,最后输出的是Name: Melania Trump。

(这里的继承机制是主动继承,也就是子类可以选择主动去继承父类,和php中的extends是一样的,子类去extends父类)

总结一下,对于对象son,在调用son.last_name的时候,实际上JavaScript引擎会进行如下操作:

在对象son中寻找last_name 如果找不到,则在son.__proto__中寻找last_name 如果仍然找不到,则继续在son._proto_.__proto__中寻找last_name 依次寻找,直到找到null结束。比如,Object.prototype的proto就是null

JavaScript的这个查找的机制,被运用在面向对象的继承中,被称作prototype继承链。

每个构造函数(constructor)都有一个原型对象(prototype) 对象的__proto__属性,指向类的原型对象prototype JavaScript使用prototype链实现继承机制

原型组成的链,对象的__proto__是原型,而原型也是一个对象,也有__proto__属性,原型的__proto__又是原型的原型,就这样可以一直通过__proto__向上找,这便是原型链,当向上找找到Object的原型的时候,这条原型链便算结束了。

原型链污染是什么

第一章中说到,foo.proto指向的是Foo类的prototype。那么,如果我们修改了foo.proto中的值,是不是就可以修改Foo类呢?

做个简单的实验:

// foo是一个简单的JavaScript对象
let foo = {bar: 1}// foo.bar 此时为1
console.log(foo.bar)// 修改foo的原型(即Object)
foo.__proto__.bar = 2// 由于查找顺序的原因,foo.bar仍然是1
console.log(foo.bar)// 此时再用Object创建一个空的zoo对象
let zoo = {}// 查看zoo.bar
console.log(zoo.bar)
最后,虽然zoo是一个空对象{},但zoo.bar的结果居然是2:
123456789101112131415161718

原因也显而易见:因为前面我们修改了foo的原型foo.__proto__.bar = 2,而foo是一个Object类的实例,所以实际上是修改了Object这个类给这个类增加了一个属性bar,值为2。

后来,我们又用Object类创建了一个zoo对象let zoo = {},zoo对象自然也有一个bar属性了

那么,在一个应用中,如果攻击者控制并修改了一个对象的原型,那么将可以影响所有和这个对象来自同一个类、父祖类的对象。这种攻击方式就是原型链污染。

(这样相当于给类添加了新的属性,而这个对象中也有bar这个属性,所以类的改变并不会影响到已经创建好的对象的属性,但是新创建的对象就不一样了)

1.首先我们要知道 构造函数.prototype指向的是一个对象(原型)

2.任何对象都有一个原型对象,这个原型对象由对象的内置属性__proto__指向它的构造函数的prototype指向的对象,即任何对象都是由一个构造函数创建的

3.只有构造函数内才有ptorotype属性

4.每个对象都内含有一个属性:__proto__,也就是说就算对象里面没有对这个属性进行赋值,那么也是有这个属性的

5.原型链的核心就是依赖对象__proto__的指向,当访问的属性在该对象不存在时,就会向上从该对象构造函数的prototype的进行查找,直至查找到Object时,就没有指向了。如果最终查找失败会返回undefined或报错

哪些情况下原型链会被污染?

在实际应用中,哪些情况下可能存在原型链能被攻击者修改的情况呢?

我们思考一下,哪些情况下我们可以设置__proto__的值呢?其实找找能够控制数组(对象)的“键名”的操作即可:

(因为对象和属性之间的表达方式很多,与数组的表达方式是一样的)

对象merge 对象clone(其实内核就是将待操作的对象merge到一个空对象中) 以对象merge为例,我们想象一个简单的merge函数:

function merge(target, source) {for (let key in source) {if (key in source && key in target) {merge(target[key], source[key])} else {target[key] = source[key]}}
}

这里如果我们想象一下,如果我们让key是__proto__,的话那么是不是就可以对原型造成影响,最终影响到实例化出来的类呢?

我们用如下代码实验一下:

但是我们发现 这里的c并没有被污染

这是因为这里我们let o2 = {a: 1, "__proto__": {b: 2}}中的proto已经作为的是o2的原型,也就是说这里o2[__proto__]={b:2}(一个对象)并没有被解析成为键名,也就是说这里我们取到的键就只有a,b也就是o1[a]=1,o1[b]=2

所以我们就要使用JSON.parse

所以说我们代码改成这样:

function merge(target, source) {for (let key in source) {if (key in source && key in target) {merge(target[key], source[key])} else {target[key] = source[key]}}
}
let o1 = {}
let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
merge(o1, o2)
console.log(o1.a, o1.b)//1,2o3 = {}
console.log(o3.b)//2

注意let o2 = {"a": 1, "proto": {"b": 2}}这种写法和let o2 = {a: 1, "__proto__": {b: 2}}写法结果是一样的

分析 :

如果是第一种情况 (没有JSON.parse的情况),我们上面谈到,在进行键值赋值之前就会把proto解析掉,让其指向其构造函数的prototype指向的对象,也就是说原型o2的原型对象就成了{"b":2},就不是最上层的Object,就达不到污染的目的

这个时候我们看我们的o2对象 :

只有一个对象

我们查看它__proto__指向的对象

那么我们继续往上面读取一下 :

发现才是最上层的Object.prototype对象,并且没有任何属性

我们知道我们给对象添加属性都是直接在后面加上.(点),然后在.(点)的后面加上属性的值

我们来看看o1:

这也证实了proto确实没有被当做键名来给a

如果我们这里能够达到这个效果:a.__proto__.b=2的话不就污染到了嘛,因为a的上一层就是Object

所以我们看看加了JSON.parse的情况,这个会把我们的属性名当做键名来解析我们来分析一下流程 :

for (let key in source) {if (key in source && key in target) {merge(target[key], source[key])} else {target[key] = source[key]}}
let o1 = {}
let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
merge(o1, o2)

这里 首先加上了JSON.parse的时候这个时候__proto__就会被当做键名了:

赋值过程中,首先会是o1[a]=o2[a]=1,

然后就回到proto这个键名,由于上面我们提及到只要是对象都会有一个__proto__属性,所以这里会进入到if语句里面,也就是说两个对象都有__proto__这个键名

接下来的赋值就是 :

target会变成o1[__proto__],source会变成o2[__proto__],接下来key就变成了b了,然后就会进行:

o1[__proto__] [b]=o2[__proto__] [b]=2(o2[__proto__]就是{"b":2},然后[b]就相当于是.b

这里o1[__proto__] [b]就相当于o1.__proto__.b=2也相当于Object.prototype.b=2

这样就相当于给最顶层的Object.prototype所指向的对象添加了属性

所以我们随便创建一个对象也就有了b这个属性

这就是所谓的原型链污染的常见基础分析了

-------------------------------------------------------------------------------------------何秋莲  ❥(^_-)  ❥(^_-)-----------------

js原型链污染(超详细)相关推荐

  1. JavaScript原型链污染攻击

    前言 最近在看js的时候看到p神的一篇关于js原型链污染的文章,学习一下. 下面转自p神:深入理解 JavaScript Prototype 污染攻击 还有一篇案例关于js原型链污染的ctf题:从一道 ...

  2. Kibana未授权访问漏洞记录(CVE-2019-7609,Kibana的RCE,原型链污染,端口:5601)

    Kibana介绍 Kibana是一个开源的分析与可视化平台,设计出来用于和Elasticsearch一起使用的.你可以用kibana搜索.查看存放在Elasticsearch中的数据.Kibana与E ...

  3. XSS注入进阶练习篇(三) XSS原型链污染

    XSS原型链污染 1.原型链的概念 1.1 构造函数的缺点 1.2 prototype 属性的作用 1.3 原型链 1.4 `constructor`属性 1.5 `prototype`和`__pro ...

  4. Javascript Prototype污染攻击(原型链污染,Bugku-web-sodirty wp)

    prototype 它表示原型,样本,标准. 在javascript中,你使用构造函数时会创建一些属性和方法. 在构造方法时,你书写了函数的内容,那么,当你每创建一次对象时就会执行一次函数内容并将方法 ...

  5. 详解JS原型链与继承

    详解JS原型链与继承 JavaScript 目录 摘自JavaScript高级程序设计: 概念 确定原型和实例的关系 原型链的问题 借用构造函数 组合继承 原型继承 寄生式继承 寄生组合式继承 new ...

  6. nodejs原型链污染

    参考两位大佬的博客: 深入理解 JavaScript Prototype 污染攻击 | 离别歌 (leavesongs.com) 继承与原型链 - JavaScript | MDN (mozilla. ...

  7. 简单粗暴地理解js原型链–js面向对象编程

    简单粗暴地理解js原型链–js面向对象编程 作者:茄果 链接:http://www.cnblogs.com/qieguo/archive/2016/05/03/5451626.html 原型链理解起来 ...

  8. 从实现角度分析js原型链

    从实现角度分析js原型链 欢迎来我的博客阅读:<从实现角度分析js原型链> 网上介绍原型链的优质文章已经有很多了,比如说: https://github.com/mqyqingfeng/B ...

  9. JS 原型链图形详解

    JS原型链 这篇文章是「深入ECMA-262-3」系列的一个概览和摘要.每个部分都包含了对应章节的链接,所以你可以阅读它们以便对其有更深的理解. 对象 ECMAScript做为一个高度抽象的面向对象语 ...

最新文章

  1. 高效职场人不得不懂的“脑”知识
  2. 机器学习:基于关联规则的多标签分类器
  3. npm: 权限阻止修复
  4. python怎样实现封装_大牛教你如何封装 Python 代码,实现自动发送邮件只需三行代码...
  5. 为什么已有Elasticsearch,我们还要重造实时分析引擎AresDB?
  6. Chrome 浏览器扩展 - Dark Web - Dark Theme for Chrome
  7. h5应用 vue 钉钉_uniapp开发一个小视频应用(一)
  8. 页面加载完毕执行多个JS函数
  9. mybatis-plus -- mapper中foreach循环操作(新增,或修改)
  10. [礼仪大赛/模特比赛策划方案]现场场景描述
  11. android office转pdf插件,Office自带Word转PDF插件 让office的另存为可存储为PDF文件
  12. 2021-10-18
  13. 华为OSN1500B故障应急处理
  14. 软件测试肖sir___项目讲解之银行项目
  15. 解决Ubuntu16.04解压cudnn文件时报错could not create a hard link file
  16. js原生往父元素中添加子元素
  17. 电子邮件群发软件哪种好 电子邮件群发软件怎么用
  18. linux读和写线程同步,Linux:使用读写锁使线程同步
  19. 虚拟摄像头/无人直播效果分析,可替抖音/微信
  20. 平凡之路_2022年

热门文章

  1. Qml学习记录 一(风车动画详细建造步骤)
  2. 服务器 16路直连 英特尔,16核超猛神U:Intel Xeon D-1587性能测试
  3. 【Python】Pandas通过索引的方式去重df[~df.index.duplicated()]
  4. Linux深入探索04-Bash shell
  5. 线性代数Python计算:消元法与矩阵初等变换
  6. 【必读】关于赞赏的说明
  7. python极简教程_Python 极简教程(一)前言
  8. 设置显示实体的颜色 byLayer/byBlock
  9. Mongodb 之 $elemMatch 作用
  10. java rx.observable_Rxjava2 Observable的错误处理操作详解及实例