Advertisement
Advertisement


Open Redirect vulnerability in javascript/jquery


Question

I'm trying to sanitize my code to address all the Open Redirect vulnerabilities. For all my c# code I applied a fix to check if the URL supplied to Response.Redirect is from the same domain as the application. If not then throw an exception.

The question I have is about the open redirect instances in my .js code. The code flagged as vulnerable is:

window.open('Help/Admin/webhelp/' + helpFile, '_blank', 'toolbar=no, menubar=no, status=yes, scrollbars=yes, resizable=yes');

httpReqObject.open("GET", 'GetHelpLink.ashx?modid=' + _AdminHelpContext, true);

window.open('viewcontents.aspx?did=' + grid.rows[i].cells[gridCell.docID].innerText, "toobar=0,menubar=0,resizable=1")

What is the best way to address this Open Redirect vulnerability in my javascript code?

Thanks.

2014/11/18
1
3
11/18/2014 8:56:15 PM

Accepted Answer

Here's what I've come up with to address this issue. I agree this is not one of the most elegant solution and might need some refinements but it does satisfy my basic requirement of not allowing user to navigate to the URL that is out of the application domain:

    function LaunchHelp(surl) {
        try {            
            if (validateURL(surl))
                window.open(surl, '_blank', 'toolbar=no,menubar=no,status=yes');
            else {
                throw new InvalidURLException();
            }
        } catch (e) {
            if (e instanceof InvalidURLException)
                alert(e.message);
        }
    }

    function InvalidURLException() {            
        this.message = "An attempt was made to open a webpage of foreign domain. No allowed.";
        this.toString = function() {
            return this.message
        };
    }

    function validateURL(surl) {
        var url = parseURL(surl);
        var urlHostname = url.hostname.trim();

        if (urlHostname == '') {
            return true;
        }
        else {
            if (urlHostname.toUpperCase() == location.hostname.trim().toUpperCase()) {
                return true;
            }
            else
                return false;
        }            
    }

    function parseURL(url) {
        var a = document.createElement('a');
        a.href = url;
        return {
            source: url,
            protocol: a.protocol.replace(':', ''),
            hostname: a.hostname,
            host: a.host,
            port: a.port,
            query: a.search,
            params: (function () {
                var ret = {},
                    seg = a.search.replace(/^\?/, '').split('&'),
                    len = seg.length, i = 0, s;
                for (; i < len; i++) {
                    if (!seg[i]) { continue; }
                    s = seg[i].split('=');
                    ret[s[0]] = s[1];
                }
                return ret;
            })(),
            file: (a.pathname.match(/\/([^\/?#]+)$/i) || [, ''])[1],
            hash: a.hash.replace('#', ''),
            path: a.pathname.replace(/^([^\/])/, '/$1'),
            relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [, ''])[1],
            segments: a.pathname.replace(/^\//, '').split('/')
        };
    } 

I had to check for hostname as empty string for the scenario where a relative path ('Help/Admin/webhelp/') is supplied to the LaunchHelp method. In this case the parseURL returns a blank hostname. I stole the "parseURL" method from here.

Any suggestions/comments/questions are most welcome.

2014/11/20
3
11/20/2014 4:19:03 PM