This is the second time I open this post because I didn't do a good debug but my solution, a sort of personal brainstorming, was good enough to open one more time this post after few changes :)
This is my proposal:
(function(m){function $(c,t){t=c[m];delete c[m];try{eval(""+c)}catch(e){c[m]=t;return 1}};return $(Array)&&$(Object)})("toString")
exactly 130 byte to solve (I suppose) Array and Object modified constructor problems.
(function(m){function $(c,t){t=c[m];delete c[m];try{new(function(){}).constructor("",""+c)}catch(e){c[m]=t;return 1}};return $(Array)&&$(Object)})("toString")
exactly 158 byte to solve (I suppose) Array and Object modified constructor problems.
Let me explain this function concept.
Step 1 - There's no way to know if a constructor is nativeThis is the first problem, we can't believe on a generic object constructor for, at least, these two reason:
- a constructor, as I wrote on MDC too, is not read only
- there isn't any official method to know if a part of code is native or not, and if it is implemented, it should be changed by malicious arbitrary code
Since a constructor should be redefined in some browser (first of all, FireFox)
function Array(){ /*doStuff*/ };
is really hard to know if this new constructor is native code or not.
You could create a new original, empty, scope (using for example an iframe), then You can check if a variable constructor, in this new scope, is equal to original one, for example, a generic Array in a generic window.
The only way to know if a constructor was inherited from JavaScript core is its string rappresentation, usually something like:
function Array() {
[native code]
}
This is a common native code string rappresentation, but as You know JavaScript is object oriented and every object has a native toString method that should be override/overwite as every other public method.
function Array(){};
Array.toString = function(){
return "function Array(){\n\t[native code]\n}"
};
alert(Array);
This means that we can't believe on string rappresentation too ... and that's why I thought about next step.
Step 2 - native code cannot be evaluatedThe uniq way to know if a method or a constructor is inherited from JavaScript core is the "
[native code]" string inside its string value.
At the same time You can't evaluate a native code because it isn't a replicable JavaScript code, so a
try...catch like this one should be a
trick to know if code is native or not because in this last case it will not make code executable:
function isNativeCode(methodOrConstructor){
var result = false;
try{eval(""+methodOrConstructor)}
catch(e){result = true};
return result;
};
alert([
isNativeCode(Array), // true
isNativeCode(String.replace), // true
isNativeCode((1).constructor), // true
isNativeCode(function(){}) // false
]);
As I said, overwriting toString method should produce a sort of
native code simply and quickly:
function Mine(){};
Mine.toString = function(){
return "[native code]"
};
alert(isNativeCode(Mine)); // true
This is the reason I thought about next final step.
Step 3 - enumerable methods should be deleted!At this point, the biggest problem is the ability to reply native code string, using for example a toString method.
Is it possible to solve? Likely sure, using a delete keyword!
function Array(){};
Array.toString = function(){
return "I'm an Array";
};
alert(Array); // I'm an Array
delete Array.toString;
alert(Array); // function Array(){\n}
Amazing, I can remove arbitrary toString method to know original value ... but does delete work without problems with native constructor too? Of course, it's on core ;)
alert(Array.toString());
// function Array(){\n\t[native code]\n}
delete Array.toString;
alert(Array.toString());
// function Array(){\n\t[native code]\n}
Well done ... but this should be quite obtrusive because some library (or some developer) should redefine toString method for its scope ... that's why I decieded to assign one more time toString method, after deleting them, obviously ... and this is my first proposal, with details:
// anonymous private scope function, accept one argument
(function(m){
// private useful dollar function
// accepts 2 arguments, one for constructor
// and one for lazy programming
function $(c,t){
// second argument is used to save old toString method
t=c[m];
// delete removes constructor toString
delete c[m];
// check if constructor contains native code
// (not usable, not evaluable)
try{eval(""+c)}
// if eval fails, constructor contains
// [native code]
catch(e){
// so I can add safely old toString method
// (is not a problem if it is native or not)
c[m]=t;
// and return a "true" value
return 1
}
};
// at this point I just need to call
// my dollar function to know
// if Array and Object are native constructors
return $(Array)&&$(Object)
})
// for size reasons, I send toString method name
// using "m" var multiple times inside function
("toString")
How to use this runtime private scope function?This is just an example that should be used before every JSONString to value convertion:
if((function(m){function $(c,t){t=c[m];delete c[m];try{eval(""+c)}catch(e){c[m]=t;return 1}};return $(Array)&&$(Object)})("toString"))
alert("I can decode a JSON string");
else
alert("JSON decoding is corrupted");
And that's all folks, You can view a basic example in
this page and a failed
hack example in
this one.
Finally, this inline function should work with every Ajax ready browser, successfully tested on IE 5, 5.5, 6, 7, FireFox 1, 1.5, 2 and Opera 8, 9.
I'm waiting for Safari 1 or 2 behaviour, as konqueror or other browsers (but I'm quite sure, this time this proposal should work correctly).
If You find a way to crack this solution, please tell me (us) :D
Update - 04/04/2007
This is a revisited version dedicated for XMLHttpRequest native object
if((function(c,m,t){t=c[m];delete c[m];if(/^\[XMLHttpRequest\]$/.test(c)){c[m]=t;return 1}})(XMLHttpRequest,"toString"))
alert("Valid XMLHttpRequest");
else
alert("XMLHttpRequest is corrupted");
Same concept, same logic ... and should be as secure as first proposal for Array and Object constructors.
Try them:
function XMLHttpRequest(){};
XMLHttpRequest.toString = function(){
return "[XMLHttpRequest]"
};
XMLHttpRequest.constructor = Object;
if((function(c,m,t){t=c[m];delete c[m];if(/^\[XMLHttpRequest\]$/.test(c)){c[m]=t;return 1}})(XMLHttpRequest,"toString"))
alert("Valid XMLHttpRequest");
else
alert("XMLHttpRequest is corrupted");
Update - 04/04/2007Do You worry about eval?
if(eval === (new function(){}).eval)
alert("OK eval");
else
alert("eval is corrupted");
And now we just need to pray that deprecated object.eval will survive for some year :DInstant Update - 04/04/2007damn ... Object.prototype.eval should redefine generic object eval method ... uhm, please let me think about a solution and sorry for precedent update.
Update - 05/04/2007
kentaromiura gives me a nice idea ... He wrote them next post.
Function can eval() code in a safe way.
You can redefine Function itself but in this case native behaviour will be lost so I suppose this should be the better way to be sure that code evaluation and Array/Object constructors are not modified.
var result, code = '[1,2,3]';
if((function(m){function $(c,t){t=c[m];delete c[m];try{new Function("",c)}catch(e){c[m]=t;return 1}};return $(Array)&&$(Object)})("toString"))
result = new Function("","return "+code)();
Is this the securest way, for JavaScript, to know if code has been cracked?Instant Updateno man ...
function Function(a,b){
// Array = function(){} ...
eval("function f(){"+b+"}");
return f;
};
alert(new Function("","return [1,2,3]")());
:(
Important Update - 05/04/2007I found a way to solve eval problems,
look here to know more.
This is the last version, it should be the best way to know if Array and / or Object were cracked.
/*
function Array(){};
Array.toString = function(){
return "function Array(){\n\t[native code]\n}"
};
//*/
if(
(function(m){function $(c,t){t=c[m];delete c[m];try{new(function(){}).constructor("",""+c)}catch(e){c[m]=t;return 1}};return $(Array)&&$(Object)})("toString")
)
alert("Array and Object constructors are OK");
else
alert("Corrupted Array and Object constructor");
With this concept I should be shure that XMLHttpRequest object is native and not re-defined.
Here You can read my last proposal for XMLHttpRequest check:
if((function(x,c,m,t){t=x[m];delete x[m];if(new(function(){})[c]("c","return ("+x+")[c]!==(function(){})[c]")(c)){x[m]=t;return 1}})(XMLHttpRequest,"constructor","toString"))
alert("XMLHttpRequest is OK");
else
alert("XMLHttpRequest is Corrupted");
It seems to be safe as function(){} code evaluation is.
If XMLHttpRequest is not native, it's a function and removing, using delete, its toString method, it should be a constructor and a constructor has a function(){} constructor, isn't right?