JavaScript闭包漏洞与修补措施

请先看下面一段代码

javascript 复制代码
	var obj = (function () {
	  var sonObj = {
	    a: 1,
	    b: 2
	  }
	  return {
	    get: function (v) {
	      return sonObj[v]
	    }
	  }
	})()

可以看出,这是一段很典型的js闭包代码,可以通过obj调用get方法传一个参数,如果传的是a就可以得到闭包内的对象sonObj.a

javascript 复制代码
	var obj = (function () {
	  var sonObj = {
	    a: 1,
	    b: 2
	  }
	  return {
	    get: function (v) {
	      return sonObj[v]
	    }
	  }
	})()
	console.log(obj.get('a'))

如下,正确的获取到了sonObj的属性a

这是一个典型的闭包场景,这样做的目的是为了屏蔽这个obj,不让外边直接访问它,只能读取它的某一个属性,这样就保护了数据的完整性

但这样做有一个问题

,那就是没有处理js闭包的漏洞,给的权限太大了

用户可以通过,obj.get访问到sonObj的任何成员,包括prototype上的成员

所以我们就可以利用可以访问prototype来达到我们想要做的事

我们都知道对象上的value上的valueOf这个方法会返回对象自身

也就是说,我们能通过

javascript 复制代码
obj.valueOf()

来获取到这个对象,方向有了,但是这样还不够.如下

javascript 复制代码
var obj = (function () {
  var sonObj = {
    a: 1,
    b: 2
  }
  return {
    get: function (v) {
      return sonObj[v]
    }
  }
})()
console.log(obj.get('valueOf')())

如上图,报错了

Uncaught TypeError: Cannot convert undefined or null to object

无法将未定义或 null 转换为对象

为什么会出现这种问题呢?

这是因为this指向的问题

因为我们只有通过sonObj调用valueOf的时候,才能返回sonObj对象

而obj.get('valueOf')()明显不是,是通过get方法获取到了valueOf这个方法本身,然后通过这个方法本身去调用的,那么这时候this的指向就变成了全局

所以这种方法是行不通了,那需要怎么办呢?

很简单,我们只需要让sonObj的某一个成员,在被读取的时候,返回它自身就好了,

如下,我们让object的原型上添加一个方法,让这个方法被访问的时候,返回它

javascript 复制代码
Object.defineProperty(Object.prototype,'aaa',{
	get(){
		return this
	}
}

这样,当访问aaa这个属性的时候,sonObj没有这个成员,就会去prototype上找,然后就会调用prototype上的aaa方法,然后就把自己返回出去了,闭包也就破解了

javascript 复制代码
	var obj = (function () {
	  var sonObj = {
	    a: 1,
	    b: 2
	  }
	  return {
	    get: function (v) {
	      return sonObj[v]
	    }
	  }
	})()
	Object.defineProperty(Object.prototype,'aaa',{
		get(){
			return this
		}
	})
	console.log(obj.get('aaa'))

诺,sonObj就到手了

那话又说回来了,该怎么防御呢?

简单,它不是原型上整活吗?,我们让sonObj原型指向null,欸,我没有原型了,也就不存在这种错误了

头痛?把脑袋砍了,就再也不会头痛了,简直是太妙了~

javascript 复制代码
	var obj = (function () {
	  var sonObj = {
	    a: 1,
	    b: 2
	  }
	  Object.setPrototypeOf(sonObj,null)
	  return {
	    get: function (v) {
	      return sonObj[v]
	    }
	  }
	})()
	Object.defineProperty(Object.prototype,'aaa',{
		get(){
			return this
		}
	})
	console.log(obj.get('aaa'))

但是在实际开发中一般不这么做,因为原型树上可能有别的方法能用得上,所以我们可以在sonObj的方法内加个判断,如果是对象上的成员就让他正常返回,如果不是就返回undefinded,

javascript 复制代码
	var obj = (function () {
	  var sonObj = {
	    a: 1,
	    b: 2
	  }
	  return {
	    get: function (v) {
	    if(obj.hasOwnProperty(v))
	      return sonObj[v]
	      return undefined
	    }
	  }
	})()
	Object.defineProperty(Object.prototype,'aaa',{
		get(){
			return this
		}
	})
	console.log(obj.get('aaa'))

不过这样写其实又出现了新的问题,关于直接手写undefined的问题,但是这里就不展开说了

相关推荐
超绝大帅哥4 分钟前
为什么回调函数不是一种好的异步编程方式
javascript
jump_jump11 分钟前
Ripple:一个现代的响应式 UI 框架
前端·javascript·前端框架
夏天想20 分钟前
element-plus的输入数字组件el-input-number 显示了 加减按钮(+ -) 和 小三角箭头(上下箭头),怎么去掉+,-或者箭头
前端·javascript·vue.js
清风徐来QCQ1 小时前
SpringMvC
前端·javascript·vue.js
Swift社区1 小时前
ArkTS Web 组件里,如何通过 javaScriptProxy 让 JS 同步调用原生方法
开发语言·前端·javascript
Hi_kenyon2 小时前
快速入门VUE与JS(二)--getter函数(取值器)与setter(存值器)
前端·javascript·vue.js
全栈前端老曹2 小时前
【前端路由】React Router 权限路由控制 - 登录验证、私有路由封装、高阶组件实现路由守卫
前端·javascript·react.js·前端框架·react-router·前端路由·权限路由
zhuà!2 小时前
uv-picker在页面初始化时,设置初始值无效
前端·javascript·uv
摸鱼的春哥2 小时前
实战:在 Docker (Windows) 中构建集成 yt-dlp 的“满血版” n8n 自动化工作流
前端·javascript·后端
_Rookie._2 小时前
关于迭代协议:可迭代协议和迭代器协议,生成器函数 生成器对象的理解
javascript·python