5

JavaScript makes it easy to overwrite properties and functions of the global object. I'd like to find a way to check if the original version of a global property has been replaced.

Consider someone putting this in their HTML:

<script type="text/javascript">
    window.encodeURIComponent = eval;
</script>
<script type="text/javascript" src="myscript.js"></script>

If myscript.js calls the encodeURIComponent function somewhere, it will now behave unpredictably. So is there a way I can check inside myscript.js if someone has overwritten that function before I use it?

GOTO 0
  • 42,323
  • 22
  • 125
  • 158

5 Answers5

8

The only thing I know is a straightforward approach with analysis of string representation of the function. Normally, the code

window.encodeURIComponent.toString()

should produce something like this:

function encodeURIComponent() { [native code] }

which can be easily parsed for key info function encodeURIComponent.

If the function was overwritten by eval, as in your example, you'll get:

function eval() { [native code] }

In general, for checking window properties, you can create a fake iframe and compare window.[property].toString() with iframe.contentWindow.[property].toString(). If the comparison gives false, the property has been changed.

Stan
  • 8,683
  • 9
  • 58
  • 102
  • This is a really clever and cross-browser way of doing it. – sg3s Apr 22 '12 at 08:46
  • Thanks Stan. Do you also know how to ensure that the toString property of `eval` hasn't been overwritten with something like `function () { return "function encodeURIComponent() { [native code] }"; }`? – GOTO 0 Apr 22 '12 at 09:42
  • instead of parsing and calling `toString` you can simply do this `window.encodeURIComponent.name`.. ANYWAY there is more preciese method to achive this http://stackoverflow.com/a/10266791/474290 – obenjiro Apr 22 '12 at 09:43
  • @ft1: I'm afraid, I don't know a solution. – Stan Apr 22 '12 at 15:13
  • For anyone looking to use this in a security context, you cannot rely on this check unless you can ensure there is no malicious code run before it. A malicious library can overwrite properties and render this check useless. – Andreas Gassmann May 31 '19 at 10:51
3

One interesting way to do this inside one script is to compare function prototype

By default - typeof window.encodeURIComponent.prototype === "undefined"

But if someone redefines this function by

window.encodeURIComponent = function() { eval(); } we will get

typeof window.encodeURIComponent.prototype === "Object"

PS: this method is more reliable then others, but it won't give you 100% gurante. JavaScript is all objects and all in runtime.. just live with this..

UPDATE you can combine both methods.. mine and @Stans..

this example don't work because I wasn't using eval - eval Is also having prototype "undefined" by default.. so you can do this

window.encodeURIComponent.name === "encodeURIComponent" 
//to make shure that user won't use EVAL 
&& typeof window.encodeURIComponent.prototype === "undefined" 
//to make shure that user won't use self defined function
obenjiro
  • 3,665
  • 7
  • 44
  • 82
  • Ai_boy, I can't seem to reproduce that. `typeof window.encodeURIComponent.prototype` is `"undefined"` in both cases. – GOTO 0 Apr 22 '12 at 09:52
1

This is browser specific and definitely will not work for non-functions, but:

Calling a function's toString method should produce something like:

Chrome:

"function encodeURIComponent() { [native code] }"

Firefox:

"function encodeURIComponent() {
    [native code]
}"

IE 7/8/9:
"
function encodeURIComponent() {
    [native code]
}
" 

Observe that the function's name matches the property's name, and its body is replaced by "[native code]". The idea is to remove all whitespace from this string and compare it to the expected result, "functionxxx(){[nativecode]}".

I have no idea if it works for all browsers/functions, that's trial and error:

var pattern = 'function' + propertyName + '(){[nativecode]}';
var func = window[propertyName].toString();
if(func.replace(/\s+/g, '') !== pattern) {
    throw new Error("Property window." + propertyName + " has been modified!");
}
DCoder
  • 12,962
  • 4
  • 40
  • 62
1

How about this?

function isNativeWindowProperty(propertyName) {
    var result = false;
    var iframe = document.createElement('iframe');
    iframe.src = 'javascript:;';
    document.getElementsByTagName('body')[0].appendChild(iframe);
    if (window[propertyName].toString() === iframe.contentWindow[propertyName].toString()) {
        // check window[propertyName].toString override
        if (window[propertyName].toString.toString() === iframe.contentWindow[propertyName].toString.toString()) {
            result = true;
        }
    }
    iframe.parentNode.removeChild(iframe);
    return result;
};

console.log(isNativeWindowProperty('alert'));  // true

window.alert = function() {};
console.log(isNativeWindowProperty('alert'));  // false

window.alert.toString = function() {
    return 'function alert() { [native code] }';
};
console.log(isNativeWindowProperty('alert'));  // false
Mrskman
  • 332
  • 2
  • 10
  • Maybe you could add some text to explain how your code answers the queston? – Kmeixner May 05 '15 at 14:18
  • Interesting approach - although `document.createElement` could itself have been monkey-patched and might tinker with contents of the created iframe... – mindplay.dk Sep 07 '20 at 12:52
  • I developed this idea and some others into a script that scans the `window` object for modified constructors and class-methods - I posted the result in a similar thread [here](https://stackoverflow.com/a/63778711/283851). – mindplay.dk Sep 08 '20 at 06:40
0

There is an EASY way to do it in JavaScript :) But you have to have access to the HTML, so you can't use this method inside of one script..

function is an OBJECT.. so we can save a link to an object and just compare those links. Just think of a function like it a simple object. How can you compare objects?

<script type="text/javascript">
    var a = window.encodeURIComponent;  // a === window.encodeURIComponent -> true
</script>
<script type="text/javascript">
    window.encodeURIComponent = eval; // a === window.encodeURIComponent -> false
</script>
<script type="text/javascript" src="myscript.js">
    if (a !== window.encodeURIComponent) 
    {
        throw new Error('Someone redefined function');
    }
</script>
obenjiro
  • 3,665
  • 7
  • 44
  • 82