为啥用变量调用数组索引是不好的做法?

Posted

技术标签:

【中文标题】为啥用变量调用数组索引是不好的做法?【英文标题】:Why is it bad pratice calling an array index with a variable?为什么用变量调用数组索引是不好的做法? 【发布时间】:2017-12-06 13:02:52 【问题描述】:

我目前正在用 javascript 开发一个小游戏,我正在使用 Codacy 来审查我的代码并帮助我清理它。

最常见的错误之一是 Generic Object Injection Sink (security/detect-object-injection)。

当我尝试使用变量访问数组中的值时会发生这种情况。就像在这个例子中一样:

function getValString(value)

    var values = ["Mis&eacuterable", "Acceptable", "Excellente", "Divine"];
    return values[value];

function 用于在屏幕上显示项目的值字符串。它接收一个“值”,可以是 0、1、2 或 3,并返回值的字符串。

现在这是我的问题:

Codacy 告诉我应该禁止使用 var[var],因为它会导致安全问题,而且由于我对 Javascript 还比较陌生,所以我想知道为什么以及在这种情况下有哪些好的做法。

【问题讨论】:

代码看起来不错。但是,在这里使用开关或查找表会更合适... 不,只是一张价值图:koefficient。还有一个班轮...... 两者都没有回答 OP 的问题 - 为什么将数组索引查找报告为不良安全做法,这是否有效? 对我来说似乎是因为查找依赖于外部函数参数,理论上可以由客户端操作,而客户端本身可能会导致任何不好的东西,如缓冲区溢出或任何被利用的东西。是否没有 codacity 的文档部分来解释这个问题? 我认为 Codacy 应该改进检查,因为只有当用作索引的变量是从外部接收的(例如用户输入或参数)而不是当它是局部变量(例如 for/while 循环计数器)。 【参考方案1】:

这里存在的安全问题是value 的字符串化值可能正在访问从对象的__proto__ 分层原型继承的属性,而不是对象本身的实际属性。

例如,考虑value"constructor" 的字符串文字的场景。

const property = "constructor";
const object = [];
const value = object[property];

value 在此上下文中的结果将解析为 Array() 函数 - 它作为对象原型的一部分被继承,而不是 object 变量的实际属性。此外,被访问的对象可能已经覆盖了任何默认继承的Object.prototype 属性,这可能是出于恶意目的。


通过执行object.hasOwnProperty(property) 条件检查以确保对象实际上 具有此属性,可以部分防止此行为。例如:

const property = "constructor";
const object = [];
if (object.hasOwnProperty(property)) 
    const value = object[property];

请注意,如果我们怀疑被访问的对象可能是恶意的或覆盖了hasOwnProperty方法,则可能需要直接使用从原型继承的Object hasOwnProperty:Object.prototype.hasOwnProperty.call(object, property) 当然,这假设我们的Object.prototype 尚未被篡改。

这不一定是全貌,但它确实说明了一点。


查看以下资源,其中更详细地阐述了为什么这是一个问题以及一些替代解决方案:

https://github.com/nodesecurity/eslint-plugin-security/blob/master/docs/the-dangers-of-square-bracket-notation.md Securely set unknown property (mitigate square bracket object injection attacks) utility function

【讨论】:

【参考方案2】:

这本身并不是一个坏习惯,因为您确实想开发一个系统并使其安全。很难想象一个系统的安全风险比导致该系统不存在的风险更高。

然而,不允许使用变量来动态创建/使用/更新索引实际上减少了硬编码任何索引的选项,这些索引可用于引用数组项或对象成员。

不允许索引极大地减少了您的选择,以至于它威胁到您可能想要在 Javascript 中创建的任何系统都不存在。让我们看看一些用例:

编号循环:

for (let index = 0; index < arr.length; index++) 
    //do whatever with arr[index]

当然,while 循环也是如此。

在循环中

for (let index in variable) 
    //do whatever with arr[index]

循环数

for (let item of variable) 
    // do whatever with item

动态查找值

这实际上以准无限多种方式使用,上面所有的例子都是这个的具体例子。示例:

function getItem(arr, index) 
    return arr[index];

总结

由于动态索引而对漏洞利用的恐惧,就相当于对流星击中确切位置和确切时间的恐惧。当然,我们不能排除它,但不能生活在不断的恐惧中低概率的灾难。同样,编程也是不可能的,有不合理的、偏执的恐惧。因此,与其因为存在漏洞利用的可能性而完全拒绝动态索引,我们必须参考可能的实际漏洞利用。如果不允许我们使用动态实例,那么我们要开发的任何系统,如果它不是那么简单,就不会存在。所以,无论我们害怕什么威胁,都应该受到保护。

示例:您从数据源检索值并有一个用于信用卡 IBAN 的字段。是的,如果向不是所有者的用户显示,那风险很高。但是您应该通过仅通过外部资源使用索引(例如用户浏览器发送的 POST 请求)使 IBAN 不可用来防止这种情况发生。

【讨论】:

以上是关于为啥用变量调用数组索引是不好的做法?的主要内容,如果未能解决你的问题,请参考以下文章

在锁中调用方法是不好的做法吗? [关闭]

为啥使用全局变量类(单例)是不好的做法? [复制]

为啥直接从 Servlet 访问 DAO 是一种不好的做法?

静态局部变量是不好的做法吗?

在微服务 REST api 调用中返回对象列表是不好的做法吗?

为啥用 shuffle 调用 KFold 生成器会给出相同的索引?