(萌新向)对于nodejs原型链污染中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]
        }   
     }
 }
  
  
 let o1 ={}
 let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
 merge(o1,o2)
 console.log(o1.a, o1.b)//1 2
 o3 ={}
 console.log(o3.b)//2

这段函数我看了半天没理解,交给ai一段一段理解,首先关于merge函数的判断

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

ai给出的解释是这样的

 提供的代码片段似乎是一个合并函数的一部分,目的是将 source 对象中的属性合并到 target 对象中。以下是代码的简要解释:
 ​
 条件检查:代码检查给定的 key 是否同时存在于 source 和 target 对象中。
 递归合并:如果 key 在两个对象中都存在,则调用 merge 函数(可能在其他地方定义)递归地合并这两个对象中该键的值。
 赋值操作:如果 key 只在 source 中存在,则将 source 中的该键值直接赋值给 target 对象。

我们举例说明

 假设我们有两个对象 source 和 target,它们的结构如下:
 let source = {  
     a: 1,  
     b: {  
         x: 10,  
         y: 20  
     },  
     c: 3  
 };  
 ​
 let target = {  
     b: {  
         x: 5  
     },  
     d: 4  
 };  
 这个时候我们希望将 source 对象的属性合并到 target 对象中。
 ​
 代码示例
 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]; // 直接赋值  
         }  
     }  
 }  
 ​
 merge(target, source);  
 console.log(target);  
 合并步骤解析
 处理 a:
 ​
 a 在 source 中存在,但在 target 中不存在,因此直接赋值。target 变为:
 {  
     b: { x: 5 },  
     d: 4,  
     a: 1  
 }  
 处理 b:
 ​
 b 在 source 和 target 中都存在,进行递归合并。
 进入 merge(target.b, source.b):
 x 在 source.b 和 target.b 中都存在,递归合并。
 y 在 source.b 中存在,但 target.b 中不存在,因此直接赋值。
 结果为:
 {  
     x: 10, // 被 source 中的值替代  
     y: 20  // 新增来自 source 的值  
 }  
 处理 c:
 ​
 c 只在 source 中存在,直接赋值。最终的 target 为:
 {  
     b: { x: 10, y: 20 },  
     d: 4,  
     a: 1,  
     c: 3  
 }  
 最终结果
 合并完成后,target 对象的最终结构如下:
 ​
 {  
     b: { x: 10, y: 20 },  
     d: 4,  
     a: 1,  
     c: 3  
 }  

prototype是一个类的原型属性,可以通过

 __proto__

来访问每个类的原型属性

也就是说,假设我们要向target类中合并source类中的属性,我们需要保留target中有的属性但source中没有的属性不变,并把target和source中都有的属性换成source中属性的值。而proto是每个类中的私有属性,每个类都有,我们如果merge合并target和source中的proto的值,也就是利用proto修改source的原型的值同时赋值给target类。

如果source类中有一个属性是proto,举例如下

 let source={
     a:1,
     "__proto__":{
     b:2
 }
 }
 ​
 let target={
     a:2,
 }

也就是修改了source类的原型类中的b属性为2

我们通过merge函数将source类和target类合并,这里再把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]
        }   
     }
 }

我们进行合并操作

由于source和target类中都有a属性,所以把source中的a属性的值赋值给target中的a属性,target类中a属性值变为1

又由于proto属性是每个类中共有的私有属性,所以把source中proto的值赋值给target类,此时target类变为

 {
     a:1,
     "__proto__":{
         b:2
     }
 }

也就是把target的原型类中的b属性赋值为2,如果target类的的原型类就是object,也就达到了原型链的链头

又因为在原型链中查找属性或方法时,JavaScript 会从当前对象开始,沿着原型链(即 proto 链)向上查找,直到找到相应的属性或方法或直到到达 Object.prototype 的原型(即 null)。如果找不到,则返回 undefined

所以我们只要修改了object类中属性的值,我们就可以在object原型链下面任意类中调用object类中属性的值

举例

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

merge修改了o1类prototype原型类中的属性b为2,由于o1类再往上他的原型类就是object类,所以object类中的b属性为2

所以虽然o3类是空的,我们在o3类中调用b属性,javascript没有在o3类中找到b属性,于是顺着原型链往上找,找到了object类中的b,于是输出值 2

### JavaScript 原型链污染漏洞及其防御方法 #### 定义与危害 JavaScript 中的原型链污染是指攻击者能够修改内置对象或自定义对象的原型,进而改变这些对象的行为。一旦成功实施此类攻击,不仅会影响当前实例化对象的功能,还可能波及其他依赖相同原型的对象[^1]。 当开发者使用某些库函数(如 `lodash.merge`),而未充分考虑传入参数的安全性时,则可能导致意外地向目标对象注入恶意属性,甚至覆盖已有属性,形成严重的安全隐患[^2]。 #### 攻击示例 下面是一个简单的例子展示了如何利用原型链污染来进行攻击: ```javascript // 模拟第三方库中的不安全合并操作 function unsafeMerge(target, source) { Object.assign(target, source); } let userSettings = {}; unsafeMerge(userSettings, { __proto__: { isAdmin: true } }); console.log({}.isAdmin); // 输出:true ``` 此代码片段中,通过传递含有特殊键名 (`__proto__`) 的源对象给 `Object.assign()` 方法,实现了对默认对象原型的属性添加,使得任何创建的对象都会继承该属性[^3]。 #### 防御策略 ##### 使用严格模式 启用 ECMAScript 5 提供的严格模式可以在一定程度上防止一些常见的编程错误,并有助于检测非法访问尝试。在严格模式下,试图修改不可扩展对象上的现有属性会抛出异常而不是静默失败[^4]。 ```javascript 'use strict'; const obj = Object.freeze({}); try { obj.__proto__.pollutedProperty = 'value'; } catch (e) { console.error('Cannot add property to frozen object'); } ``` ##### 输入验证与清理 对于所有外部输入的数据,在将其应用于敏感位置之前都应经过严格的校验和净化处理。特别是要警惕那些允许指定对象结构的操作符或API调用,比如 `JSON.parse()`, `eval()`, 或者像上述提到过的 `_.merge()` 函数等[^5]。 ##### 库更与替代方案选择 定期审查所使用的第三方库版本,及时升级到最稳定版以获取官方修复补丁;必要时寻找更安全可靠的备选工具代替已知存在问题的方法实现相似功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值