Web 安全之禁止 ES9 Object.fromEntries 的滥用

随着前端技术的不断发展,新的语言特性和 API 不断涌现,其中 ES9 中的 Object.fromEntries 是一项非常强大的 API。它可以将一个由键值对组成的数组转换成一个对象。但是,如果不加限制地使用该 API,可能会带来一些安全风险。本文将详细介绍这个问题,并提供一些解决方案和建议。

Object.fromEntries 的基本用法

在介绍安全问题之前,让我们先看一下 Object.fromEntries 的基本用法。假设我们有一个由键值对组成的数组,如下所示:

const arr = [['name', 'Alice'], ['age', 20], ['gender', 'female']];

我们可以使用 Object.fromEntries 将其转换成一个对象:

const obj = Object.fromEntries(arr);
// { name: 'Alice', age: 20, gender: 'female' }

这样,我们就可以方便地将一个数组转换成一个对象了。

安全问题

虽然 Object.fromEntries 很方便,但是如果不加限制地使用它,可能会带来一些安全风险。具体来说,如果我们允许用户输入一个由键值对组成的数组,并直接将其传给 Object.fromEntries,那么用户就可以通过构造特定的输入来实现一些攻击。

例如,假设我们有一个表单,用户可以输入一些信息,并将其保存到服务器上。我们可以将表单中的数据转换成一个由键值对组成的数组,并将其保存到数据库中。然后,当用户需要查看这些数据时,我们可以将其从数据库中取出,并将其传给 Object.fromEntries,将其转换成一个对象。这样,用户就可以方便地查看自己保存的数据了。

但是,如果我们不加限制地使用 Object.fromEntries,就会存在一些安全问题。具体来说,如果用户可以构造一个恶意的数组,并将其传给 Object.fromEntries,就可以实现一些攻击。例如,假设用户输入了以下数组:

const arr = [['__proto__.isAdmin', true]];

这个数组中包含了一个名为 __proto__.isAdmin 的键,其对应的值为 true。如果我们将这个数组传给 Object.fromEntries,就会创建一个具有 isAdmin 属性的对象。更重要的是,这个对象的原型链上的 __proto__ 对象也会被修改,其 isAdmin 属性也会被设置为 true。这样,攻击者就可以利用这个对象来实现一些攻击,例如修改页面上的内容或者窃取用户的信息。

因此,我们需要限制用户输入的数组,以避免这种安全问题。

解决方案

为了避免 Object.fromEntries 的滥用,我们可以采取以下几种解决方案。

方案一:限制键的格式

首先,我们可以限制键的格式,只允许用户输入由字母、数字和下划线组成的键。这样,就可以避免用户输入一些特殊的键,例如 __proto__

function isSafeKey(key) {
  return /^[a-zA-Z0-9_]+$/.test(key);
}

function safeFromEntries(arr) {
  return Object.fromEntries(arr.filter(([key, value]) => isSafeKey(key)));
}

在这个例子中,我们定义了一个 isSafeKey 函数,用于判断一个键是否安全。如果一个键包含了除字母、数字和下划线以外的字符,就认为它是不安全的。然后,我们使用 filter 函数过滤掉不安全的键,并将剩下的键值对传给 Object.fromEntries

方案二:限制值的类型

其次,我们可以限制值的类型,只允许用户输入字符串、数字和布尔值。这样,就可以避免用户输入一些特殊的值,例如函数或者对象。

function isSafeValue(value) {
  return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
}

function safeFromEntries(arr) {
  return Object.fromEntries(arr.filter(([key, value]) => isSafeValue(value)));
}

在这个例子中,我们定义了一个 isSafeValue 函数,用于判断一个值是否安全。如果一个值的类型不是字符串、数字或者布尔值,就认为它是不安全的。然后,我们使用 filter 函数过滤掉不安全的值,并将剩下的键值对传给 Object.fromEntries

方案三:使用 JSON 序列化和反序列化

最后,我们可以使用 JSON 序列化和反序列化来避免 Object.fromEntries 的滥用。具体来说,我们可以先将用户输入的数组转换成一个 JSON 字符串,然后将其反序列化成一个对象。这样,就可以避免用户输入一些特殊的键或值。

function safeFromEntries(arr) {
  const json = JSON.stringify(arr);
  const obj = JSON.parse(json);
  return Object.fromEntries(obj);
}

在这个例子中,我们先使用 JSON.stringify 将数组转换成一个 JSON 字符串,然后使用 JSON.parse 将其反序列化成一个对象。这个对象不会包含任何特殊的键或值,因此可以直接传给 Object.fromEntries

总结

本文介绍了 ES9 中的 Object.fromEntries API,并讨论了它的安全问题。如果不加限制地使用 Object.fromEntries,就会存在一些安全风险。为了避免这种风险,我们可以限制键的格式、限制值的类型,或者使用 JSON 序列化和反序列化。这些解决方案都可以有效地避免 Object.fromEntries 的滥用,从而提高 Web 应用的安全性。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/658b6af1eb4cecbf2d0b279e


纠错
反馈