y18n引发安全漏洞,警惕javascript原型链污染

简介: 前端的安全问题不容忽视,及时的升级版本很重要,即便是非常微不足道的小组件都可能应发安全问题,来看一看y18n,它仅仅是一个用于处理i18n的npm包而已,却也能爆出高危漏洞。

2021-04-01收到了github的邮件,还以为是关于愚人节的(误),提醒我有一条Dependabot alerts,包依赖存在安全问题,当然这不是第一次了,正常情况我批准merge掉后就不会关心了,不过我发现这个包是y18n,这让我感到奇怪,这个包的功能非常简单,其实就是i18n,做语言国际化用的,逻辑应该非常简单,怎么会出安全问题呢?

我找到了这个安全问题的具体信息,他的CVE ID为CVE-2020-7774,并且上报了SNYK,代码为SNYK-JS-Y18N-1021887,SNYK对此安全问题给出了7.3的高分,并将安全类别划分为CWE-400(资源消耗不受限制),如此严重的问题是怎么回事呢?

找到具体的修复PR,在https://github.com/yargs/y18n/pull/108,commit只有一个,为https://github.com/yargs/y18n/pull/108/commits/e90e8ce71b2fd5aa27c5109884ea47525fde961f,打开这个commit,发现其实主要只改了一行代码,加了两个检测原型的单元测试,这一行代码修改如下

-    this.cache = {
   }
+    this.cache = Object.create(null)

可能有人不明白这两行代码有什么区别,使用{}创建的对象自带原型属性,而Object.create(null)是干净的,在console中就可以试出来,输入{},点开返回的内容,发现其中只有一个__proto__属性,点开这个属性可以发现其中还有constructorhasOwnProperty等等,而输入Object.create(null),返回的是一个没有任何属性的空的{}

为什么带__proto__的对象有安全隐患呢,原因很简单,__proto__是所有对象共享的,而不是一个对象独占,举一个很简单的例子,在console运行如下code

let foo = {
   }
let bar = {
   }
foo.__proto__.isBad = true
bar.isBad
//true

我们发现bar.isBad得到了true,其实此时任何原型对象都有了一个isBad,这就足以说明其危险性,而Object.create(null)是没有__proto__的,即使强行赋一个__proto__的值,也不会改变其他对象的__proto__

当然在很多时候我们发现不少项目都有直接写{}的习惯,他们都有安全问题吗?当然不是,如果你能完全控制好自己的对象,不使其收到用户输入与环境的影响,那自然是没问题的,但上文提到的cache对象并不是这样,大致阅读下index.ts的代码就可以发现,外部可以给予它任何属性,没有做任何的检查,这当然是存在严重的问题的,使用y18n的程序只需要被注入一小段以__proto__为locale代码,系统很快就会奔溃掉。

关于使用Object.freeze防止原型链污染

其实除了用Object.create(null)创建对象以外,如果适当的时机使用Object.freeze()冻结__proto__,这个问题也不会发生

const foo = {
   }
const bar = {
   }
foo.progress//progress of this foo object
foo.__proto__ = Object.freeze(foo.__proto__)
foo.__proto__.isBad = true
//foo.__proto__.isBad is undefined

freeze掉__proto__之后再对__proto__进行修改时,不会产生任何效果,因为foo已经被冻结,此时即使对象暴露在外部,全局__proto__指针也是安全的,它事实上已经是只读的,但请注意只冻结对象是没有用的,Object.freeze无法冻结整个属性链,例如

const a = Object.freeze({
   b: {
   c: 1}})
a.b.c = 2

这样修改是成功的,因为Object.freeze只冻结了b属性,但b自己也是一个对象,它的属性c是不会被冻结的,在__proto__上也是一样的,

const foo = Object.freeze({
   })
const bar = {
   }
foo.__proto__.isBad = true
bar.isBad
//true

__proto__本身被冻结了,foo.__proto__ = xx是不会生效的,但是对__proto__中属性的操作仍然都是有效的

其他注意事项

  1. 不少情况下,Map都要比Object更好,应该经常注意是否具备用Map替代Object的情况,在2016年ES6兴起的时候,国外就有社区对这个问题进行了大量交流,也有很多大牛发文响应这一观点,近年来也有很多相关的中文文章
  2. 对外部JSON输入进行安全验证,例如使用jpv 一类的验证器,不过这些组件的安全问题也是值得关注的,例如CVE-2020-17479这样伪装成数组绕过验证的神奇漏洞
  3. 防止直接的代码注入,例如在web项目的console中警告用户不要输入未知代码,例如Facebook使用多国语言在console中警告用户停止输入未知内容的行为,在electron应用中应该在发布时关闭develop面板

FYI

本文写作于2021年4月2日并发布于lyrieek的掘金,于2023年7月16日进行修订发布于lyrieek的阿里云开发者社区。

目录
相关文章
|
JavaScript 前端开发 开发者
理解JavaScript中的原型链:基础与实践
【10月更文挑战第8天】理解JavaScript中的原型链:基础与实践
|
JavaScript 前端开发
JavaScript 原型链的实现原理是什么?
JavaScript 原型链的实现原理是通过构造函数的`prototype`属性、对象的`__proto__`属性以及属性查找机制等相互配合,构建了一个从对象到`Object.prototype`的链式结构,实现了对象之间的继承、属性共享和动态扩展等功能,为 JavaScript 的面向对象编程提供了强大的支持。
|
JavaScript 前端开发
原型链在 JavaScript 中的作用是什么?
原型链是 JavaScript 中实现面向对象编程的重要机制之一,它为代码的组织、复用、扩展和多态性提供了强大的支持,使得 JavaScript 能够以简洁而灵活的方式构建复杂的应用程序。深入理解和熟练运用原型链,对于提升 JavaScript 编程能力和开发高质量的应用具有重要意义。
|
8月前
|
数据采集 JavaScript 前端开发
一站搞定原型链:深入理解JavaScript的继承机制
综上所述,可以得出: 1. 原型链是对象通过原型实现属性和方法继承的一种机制。 2. 每个对象都有一个 __proto__ 属性,指向它的原型对象。 3. 每个函数(包括构造函数)都有一个 prototype 属性,指向一个对象,这个对象的属性和方法可以被实例共享。 4. 构造函数创建对象时,新对象的 __proto__ 属性指向构造函数的 prototype 对象。 5. 继承可以通过设置原型对象实现,也可以使用 ES6 的 class 语法糖。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一
|
JavaScript 前端开发
如何使用原型链继承实现 JavaScript 继承?
【10月更文挑战第22天】使用原型链继承可以实现JavaScript中的继承关系,但需要注意其共享性、查找效率以及参数传递等问题,根据具体的应用场景合理地选择和使用继承方式,以满足代码的复用性和可维护性要求。
|
JavaScript 前端开发 开发者
探索JavaScript原型链:深入理解与实战应用
【10月更文挑战第21天】探索JavaScript原型链:深入理解与实战应用
229 1
|
JavaScript 前端开发 开发者
深入理解JavaScript原型链:从基础到进阶
【10月更文挑战第13天】深入理解JavaScript原型链:从基础到进阶
290 0
|
JavaScript 前端开发 开发者
原型链深入解析:JavaScript中的核心机制
【10月更文挑战第13天】原型链深入解析:JavaScript中的核心机制
343 0
|
JavaScript 前端开发 安全
深入理解JavaScript原型链:从基础到进阶
【10月更文挑战第13天】深入理解JavaScript原型链:从基础到进阶
223 0
|
开发者 图形学 iOS开发
掌握Unity的跨平台部署与发布秘籍,让你的游戏作品在多个平台上大放异彩——从基础设置到高级优化,深入解析一站式游戏开发解决方案的每一个细节,带你领略高效发布流程的魅力所在
【8月更文挑战第31天】跨平台游戏开发是当今游戏产业的热点,尤其在移动设备普及的背景下更为重要。作为领先的游戏开发引擎,Unity以其卓越的跨平台支持能力脱颖而出,能够将游戏轻松部署至iOS、Android、PC、Mac、Web及游戏主机等多个平台。本文通过杂文形式探讨Unity在各平台的部署与发布策略,并提供具体实例,涵盖项目设置、性能优化、打包流程及发布前准备等关键环节,助力开发者充分利用Unity的强大功能,实现多平台游戏开发。
768 0

热门文章

最新文章