JavaScript原型链污染

这篇具有很好参考价值的文章主要介绍了JavaScript原型链污染。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

在浏览某个论坛的时候,第一次看到了JavaScript原型链污染漏洞。当时非常的好奇,当时我一直以为js作为一种前端语言,就算存在漏洞也是针对前端,不会危害到后端,因此我以为这种漏洞危害应该不大。可当我看到他的漏洞危害还有可以执行任意命令的时候,发现可能我想到有点简单了。js也是可以用来做后端语言的。这篇文章就来认识一下这个漏洞。

JavaScript原型链是什么?

既然漏洞名称是JavaScript原型链污染,那么首先就要先明白JavaScript原型链是什么。

正如我们所知,Javascrip的复杂类型都是对象类型(Object),而js不是一门完全面对对象编程的语言。那么对于对象编程来说要考虑对象的继承。

js实现继承的核心就是原型链我理解的就是原型链的存在就是js中的继承机制,保证函数或对象中的方法,属性可以向下传递。

js使用了构造函数来创建对象,如下,我们可以通过构造函数来定义一个类:

// 构造函数
function Person(name, age) {
    this.name = name;
    this.age = age;
}

// 生成实例
const p = new Person('zhangsan', 18);

JavaScript原型链污染,javascript,原型模式,开发语言

可以看到这个类除了我们定义的两个属性以外,还有一个prototype的属性。prototype指向函数的原型对象,这是一个显式原型属性,只有函数才拥有该属性。

prototype也拥有两个属性:

constructor:指向原型的构造函数

prototype:指向了Object的原型

在prototype的属性中有一个_proto_,那么这个_proto_与prototype又有什么关系?

JavaScript原型链污染,javascript,原型模式,开发语言

原型prototype是类的一个属性,而所有用类实例化的对象,都将拥有这个属性中的所有内容,包括变量和方法。比如上图中的p对象,其天生就具有类Person的属性和方法。

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

也就是类可以用prototype来访问类的原型,而实例化的对象可以用_proto_来访问对象所在类的prototype属性。

总结:

其实我们只要明白一点就可以了,JavaScript原型链是js中实现继承的核心,js的对象都会执行其它的原型,最后指向的原型为null。最后关于原型链再来总结一下

1)js是通过原型链来实现继承的。

2)所有类对象在实例化的时候将会拥有prototype中的属性和方法

3)类可以使用prototype来访问类的原型对象,而实例化对象可以通过_proto_来访问类的原型对象

let f = new Foo();
f.constructor === Foo;
f._proto_ === Foo.prototype
f._proto_ === Foo.prototype
Foo._proto_ === Function.prototype

原型链污染

在了解了原型链的相关知识以后,可以来看看竟然什么是原型链污染漏洞。

上面说过实例化对象的__proto__指向了类的prototype。那么,如果我们修改了实例化对象__proto__中的值,是不是就可以修改类中的值呢?是否可以影响所有和这个对象来自同一个类、父祖类的对象?

其实这就是原型链污染的原理。我们通过修改实例化对象的__proto__中的值,污染了类本体,进而影响所有和这个对象来自同一个类、父祖类的对象。

p神的博客上有一个这样的例子,用来说明原型链污染:

JavaScript原型链污染,javascript,原型模式,开发语言

实际情况下利用分析

在实际的情况中,我们可能只能控制部分参数,那么我们怎么才能为__proto__赋值呢?

要为__proto__赋值就要求__proto__作为变量传进去并且作为键名,这种情况一般出现在下面的三种场景中:

  • 对象merge
  • 对象clone(其实内核就是将待操作的对象merge到一个空对象中)
  • 路径查找属性然后修改属性的时候

下面借用p神文章中的一个例子来看看具体操作,原文链接为:深入理解 JavaScript Prototype 污染攻击 | 离别歌

以对象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]
        }
    }
}

在合并的过程中,存在赋值的操作target[key] = source[key],那么,这个key如果是__proto__,是不是就可以原型链污染呢?

let o1 = {}
let o2 = {a: 1, "__proto__": {b: 2}}
merge(o1, o2)
console.log(o1.a, o1.b)

o3 = {}
console.log(o3.b)

结果是,合并虽然成功了,但原型链没有被污染:

JavaScript原型链污染,javascript,原型模式,开发语言

这是因为,我们用JavaScript创建o2的过程(let o2 = {a: 1, "__proto__": {b: 2}})中,__proto__已经代表o2的原型了,此时遍历o2的所有键名,你拿到的是[a, b],__proto__并不是一个key,自然也不会修改Object的原型。从下面的图中也可以看出,在o1中,参数b并没有出现在原型中。

JavaScript原型链污染,javascript,原型模式,开发语言

那么,如何让__proto__被认为是一个键名呢?

我们将代码改成如下:

let o1 = {}
let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
merge(o1, o2)
console.log(o1.a, o1.b)

o3 = {}
console.log(o3.b)

可见,新建的o3对象,也存在b属性,说明Object已经被污染

JavaScript原型链污染,javascript,原型模式,开发语言

这是因为,JSON解析的情况下,__proto__会被认为是一个真正的“键名”,而不代表“原型”,所以在遍历o2的时候会存在这个键。

再来看看o1发现,b属性是定义在原型之中的。

JavaScript原型链污染,javascript,原型模式,开发语言

merge操作是最常见可能控制键名的操作,也最能被原型链攻击,很多常见的库都存在这个问题。

js原型链污染漏洞分析

接下来用一个cve漏洞来具体再看一下这个漏洞。

3.4.0版本之前的jQuery存在一个原型污染漏洞CVE-2019-11358,PoC如下。

//代码如下,如果从前端接收一个json内容,传到后端。
//json内容:JSON.parse('{"__proto__": {"z": 123}}')

const json1 = ajax();  
jQuery.extend(true, {}, JSON.parse(json1));
console.log( "test" in {} ); // true

jQuery.extend () 函数用于将一个或多个对象的内容合并到目标对象

$.extend( [deep ], target, object1 [, objectN ] )

参数

描述

deep

可选。 Boolean类型 指示是否深度合并对象,默认为false。如果该值为true,且多个对象的某个同名属性也都是对象,则该"属性对象"的属性也将进行合并。

target

Object类型 目标对象,其他对象的成员属性将被附加到该对象上。

object1

可选。 Object类型 第一个被合并的对象。

objectN

可选。 Object类型 第N个被合并的对象。

再来看看实际的代码是如何去写入的。

首先下载jQuery,这里下载的是3.3.0版本

GitHub - jquery/jquery at 3.3.0

在src/core.js中文件中可以找到该extend函数。看过源码,可以发现该函数的正好符合上面说的合并数据的概念,那么来看看它到底会不会被污染?

JavaScript原型链污染,javascript,原型模式,开发语言

我们来动态调试一下这个程序:

引入jQuery脚本,并设置断点,进行调试

JavaScript原型链污染,javascript,原型模式,开发语言

首先根据第一个参数判断是否进行深度拷贝,然后进行第一次循环,取得参数为__proto__

JavaScript原型链污染,javascript,原型模式,开发语言

第二次循环,在__proto__中去参数进行赋值

JavaScript原型链污染,javascript,原型模式,开发语言

此时再看原型已经被污染了

JavaScript原型链污染,javascript,原型模式,开发语言

总结

js原型链污染可以说原理并不是太难懂,关键是实际中如何去利用。关于这个漏洞也是看了很多大神的文章,它们的思路真的太厉害了,我还有很多需要学习的,跟大家一起共勉。

由于本人水平有限,文章中可能会出现一些错误,欢迎各位大佬指正,感激不尽。如果有什么好的想法也欢迎交流,谢谢大家了~~

参考链接

JavaScript原型链污染原理及相关CVE漏洞剖析 - FreeBuf网络安全行业门户

深入理解 JavaScript Prototype 污染攻击 | 离别歌

再探 JavaScript 原型链污染到 RCE - 先知社区

Node.js原型链污染的利用 - FreeBuf网络安全行业门户
 

最后,推荐一款应用开发神器

关于目前低代码在技术领域很活跃!

低代码是什么?一组数字技术工具平台,能基于图形化拖拽、参数化配置等更为高效的方式,实现快速构建、数据编排、连接生态、中台服务等。通过少量代码或不用代码实现数字化转型中的场景应用创新。它能缓解甚至解决庞大的市场需求与传统的开发生产力引发的供需关系矛盾问题,是数字化转型过程中降本增效趋势下的产物。

一款好用的低代码平台——JNPF快速开发平台。近年在市场表现和产品竞争力方面表现较为突出,采的是最新主流前后分离框架(SpringBoot+Mybatis-plus+Ant-Design+Vue3。代码生成器依赖性低,灵活的扩展能力,可灵活实现二次开发。

以JNPF为代表的企业级低代码平台为了支撑更高技术要求的应用开发,从数据库建模、Web API构建到页面设计,与传统软件开发几乎没有差异,只是通过低代码可视化模式,减少了构建“增删改查”功能的重复劳动,还没有了解过低代码的伙伴可以尝试了解一下。

应用:https://www.jnpfsoft.com/?csdn

有了它,开发人员在开发过程中就可以轻松上手,充分利用传统开发模式下积累的经验。所以低代码平台对于程序员来说,有着很大帮助。文章来源地址https://www.toymoban.com/news/detail-684103.html

到了这里,关于JavaScript原型链污染的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SAP Fiori开发中的JavaScript基础知识15 - 原型,object,constructor,class,继承

    本文将介绍JavaScript中的核心概念 - 原型,并会介绍基于原型的应用场景object,constructor,class,继承。 本文会将这几个核心概念汇总在一篇博客中,因为这些概念是触类旁通的,希望对你有帮助。 在JavaScript中,几乎所有的东西都是对象,每个对象都有一个 特殊的内部属性

    2024年04月23日
    浏览(122)
  • Javascript的原型和原型链

       原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先,通过该构造函数产生的对象,可以继承该原型的属性和放法,因此原型也是对象。    实例化为对象时:    通过 .prototype 创建属性, 调用时,直接对象名.属性,就可以获取值。    原型的作

    2024年02月11日
    浏览(71)
  • 深入理解JavaScript原型与原型链

    JavaScript是一门基于原型的面向对象编程语言,它的原型和原型链是其核心特性之一。理解原型和原型链对于掌握JavaScript的面向对象编程非常重要。本文将深入探讨JavaScript原型与原型链,并通过代码举例进行说明。 在JavaScript中,每个对象都有一个原型对象。原型对象可以看

    2024年02月11日
    浏览(41)
  • javascript中的prototype;javascript中的原型链

    在JavaScript中,每个对象都有一个原型(prototype),并且原型可以有自己的原型,形成了一个链式结构,被称为原型链。这个机制是JavaScript中实现继承和对象属性查找的基础。 原型链是由对象之间的连接构成的。每个对象都有一个指向它原型的链接,这个链接可以追溯到顶层

    2024年02月20日
    浏览(42)
  • 开发语言漫谈-JavaScript

           JavaScript、Java名字很相近,但它们没有任何亲缘关系,是由不同公司开发的编程语言。Java由Sun公司(后被Oracle收购)开发,JavaScript最初是由Netscape公司开发的(当年浏览器的霸主)。JavaScript最初的名字是 LiveScript,Netscape将其命名为 JavaScript,无非是蹭 Java流量。当

    2024年04月16日
    浏览(50)
  • 【JavaScript】原型

    在 JavaScript 中,每个对象都有一个原型(prototype),它是一个对象本身,而不是一个函数。原型机制是 JavaScript 的核心特性之一,它允许对象继承另一个对象的属性和方法。 以下是关于 JavaScript 原型的基本概念和用法: 原型链: 每个对象都有一个原型,而原型本身也是一个

    2024年02月11日
    浏览(36)
  • JavaScript 原型链解析,宏任务和微任务

      目录 什么是原型链? 原型与构造函数 原型链的工作原理 实例:理解原型链 宏任务(Macro Task) 微任务(Micro Task) JavaScript 是一门基于原型的语言,而原型链是 JavaScript 中实现继承的一种机制。它允许对象通过从其他对象继承属性和方法,形成一个链式结构。当访问一个

    2024年02月14日
    浏览(27)
  • 建站系列(五)--- 前端开发语言之HTML、CSS、JavaScript

    建站系列(一)— 网站基本常识 建站系列(二)— 域名、IP地址、URL、端口详解 建站系列(三)— 网络协议 建站系列(四)— Web服务器之Apache、Nginx 建站系列(五)— 前端开发语言之HTML、CSS、JavaScript 建站系列(六)— 后端开发语言 建站系列(七)— 常用前后端框架

    2024年02月09日
    浏览(56)
  • 第3集丨JavaScript 使用原型(prototype)实现继承——最佳实战1

    在 JavaScript 中, 继承机制的基础是 原型 ,(包括内部原型 __proto__ 和 prototype )。当访问一个对象的属性时, JavaScript 引擎是这么搜索的:如果在本对象中找不到一个属性时,就会去其原型对象中找,如果原型对象中还没找到的话,就去到原型对象中的原型中去找,直到顶级

    2024年02月15日
    浏览(71)
  • 第6集丨JavaScript 使用原型(prototype)实现继承——最佳实战3

    对于继承应用来说,主要目标是将一些现有的功能归为己有。也就是说,我们在新建一个对象时,通常首先应该继承于现有对象,然后在为其添加额外的方法和属性。对此,我们可以通过一个函数调用来完成,并且在其中混合使用我们刚才所讨论的两种方式: 使用原型继承的

    2024年02月16日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包