Search code examples
javascriptjqueryasp.netajaxmicrosoft-ajax

Replacing eval() in MicrosoftAjax.js file with different code


The HTML/JS .aspx pages in my Asp.NET WebForm application use MicrosoftAjax.js file, But some security policies disallows the use of javascript eval() function. They claim that all instances of eval can be replaced by another (hopefully safer) function.

<script src="../../Scripts/MicrosoftAjax.js"></script>

How can we replace these eval() functions with different code so that the file can surpass the security validations ?


Solution

  • If you're using MicrosoftAjax.js version 4.5.2, I can safely say the following probably won't break anything

    The line numbers are a guide only - look for the specific code to replace

    The first two are easy, single line replacements

    Around line 531

    Type.parse = function (typeName, ns) {
        var fn;
        if (ns) {
            fn = Sys.__upperCaseTypes[ns.getName().toUpperCase() + "." + typeName.toUpperCase()];
            return fn || null
        }
        if (!typeName)
            return null;
        if (!Type.__htClasses)
            Type.__htClasses = {};
        fn = Type.__htClasses[typeName];
        if (!fn) {
    //replace next line
            fn = eval(typeName);
    // with next line
            fn = typeName.split('.').reduce(function(r, v) { return r && r[v]; }, window);
    //
            Type.__htClasses[typeName] = fn
        }
        return fn
    };
    

    Around line 662

    Array.parse = function (value) {
        if (!value)
            return [];
        // replace next line
        return eval(value)
        // with next line
        return JSON.parse(value)
    };
    

    Next one just comment out the lines as shown

    Around line 830

        fail: function (message) {
            this._appendConsole(message);
    // comment out the next two lines
            //if (Sys.Browser.hasDebuggerStatement)
            //    eval("debugger")
        },
    

    You can completely comment or remove the next function

    Around line 2448

    // comment out this whole function
    //Sys.Serialization.JavaScriptSerializer.deserialize = function (data, secure) {
    //    if (data.length === 0)
    //        throw Error.argument("data", Sys.Res.cannotDeserializeEmptyString);
    //    try {
    //        var exp = data.replace(Sys.Serialization.JavaScriptSerializer._dateRegEx, "$1new Date($2)");
    //        if (secure && Sys.Serialization.JavaScriptSerializer._jsonRegEx.test(exp.replace(Sys.Serialization.JavaScriptSerializer._jsonStringRegEx, "")))
    //            throw null;
    //        return eval("(" + exp + ")")
    //    } catch (a) {
    //        throw Error.argument("data", Sys.Res.cannotDeserializeInvalidJson)
    //    }
    //};
    

    the get_object method needs to be replaced

    Around line 3938

    // replace this function
        get_object: function () {
            if (!this._resultObject)
                this._resultObject = Sys.Serialization.JavaScriptSerializer.deserialize(this.get_responseData());
            return this._resultObject
        },
    // with this function
        get_object: function () {
            if (!this._resultObject) {
                this._resultObject = JSON.parse(this.get_responseData(), function wcfReviver(key, value) {
                    if (typeof value !== "string") {
                        return value;
                    }
                    var d = value.match(/^\/Date\((-?\d+)(?:[+-]\d{4}|)\)\/$/);
                    return d && d.length === 2 ? new Date(+d[1]) : value;
                });
            }
            return this._resultObject
        },
    

    And another, simple, single line replacement

    Around line 4166

        executeRequest: function (webRequest) {
            var executor = webRequest.get_executor();
            if (!executor) {
                var failed = false;
                try {
    // replace next line
                    var executorType = eval(this._defaultExecutorType);
    // with next line
                    var executorType = this._defaultExecutorType.split('.').reduce(function(r, v) { return r && r[v]; }, window);
    // 
                    executor = new executorType
                } catch (a) {
                    failed = true
                }
                webRequest.set_executor(executor)
            }
            if (executor.get_aborted())
                return;
            var evArgs = new Sys.Net.NetworkRequestEventArgs(webRequest),
            handler = this._get_eventHandlerList().getHandler("invokingRequest");
            if (handler)
                handler(this, evArgs);
            if (!evArgs.get_cancel())
                executor.executeRequest()
        }
    

    I can confirm that I applied these changes to a a development testing site, and it kept working. I even applied it to the production version of the site for one sparsely used section that, for some reason specifically loads MicrosoftAjax.js (in the rest of our site using, this file is loaded as part of a common header), and nothing broke there either - I then even tried changing the global common section, and the production site didn't skip a beat.

    That said, no warranties implied or given, if you break something you get to keep all pieces.