1

Is it possible to degrade XSS attacks from browser?

I have a special case here, I don't use cookies for authentication, I send http token headers instead of that with javascript ajax. It is possible to protect those headers with closures:

var authModule = (function (ajax, extend){
    var authModule = {
        identified: false,
        login: function (identificationFactors){
            ajax("/session", {
                method: "POST",
                data: identificationFactors,
                success: function (data, status, xhr){
                    var token = xhr.getResponseHeader("auth-token");
                    authModule.onPermissionChange({
                        identified: true,
                        ajax: function (url, settings){
                            var settings = extend({}, settings);
                            settings.headers = extend({}, settings.headers);
                            settings.headers['X-Auth-Token'] = token;
                            return ajax(url, settings);
                        }
                    });
                }
            });
        },
        logout: function (){
            authModule.onPermissionChange({
                identified: false,
                ajax: ajax
            });
        },
        onPermissionChange: function (o){
            authModule.identified = o.identified;
            $.ajax = o.ajax;
        }
    };
    return authModule;
})($.ajax, $.extend);
authModule.login({
    email: "...",
    password: "..."
});

This should work if $.ajax and $.extend both come from a secure source.

The username and password is still not protected, the DOM neither, etc... If I could load every external lib and my client side application from a single bootstrap closure without using the global namespace (attacker code usually injects javascript into the global namespace), it would be possible to protect everything on the server against xss. Without auth tokens the attacker code could not do anything on server side...

Of course I still sanitize everything on server side against xss, but in the case of an accidental xss vulnerability this would be an additional layer...

What do you think, does this worth the effort?

edit: Just for the sake of Benjamin:

<html>
<head>
<script>
var protectedDependency = (function (){
    var c = console;
    var log = console.log;
    return function (x){
        log.call(c, "protected: " + x); // <------- not secured dependency (Function.call) here, easy to forget...
    };
})();

var unprotectedDependency = function (x){
    console.log("unprotected: " + x);
};

var sandbox = (function (ajax, ajax2){
    return {
        sendToken: function (){
            ajax("my token");
            ajax2("some data");
        }
    };
})(protectedDependency, unprotectedDependency);
</script>
</head>
</body>
<script>
var injectedCode = function (){
    var log = console.log;
    var wrap = function (f){
        return function (x){
            log("stolen: " + x);
            f(x);
        };
    };
    console.log = wrap(console.log);
    protectedDependency = wrap(protectedDependency);
    unprotectedDependency = wrap(unprotectedDependency);
};
injectedCode();
sandbox.sendToken();
</script>
</body>
</html>

Go on, steal the token your can override the injectedToken with anything except: stealing it with innerHTML of the SCRIPT node, and toString/toSource of the function itself, because normally the token come from the server, so it is not in this static format.

edit2:

I accepted the answer, because this is a hard way to protect your code against XSS. It is much easier to sanitize it well on server side.

conclusion:

With great care, you can protect small parts of your code with this method, for example in my case the auth token, but by larger code it is too much effort to protect every dependency. So this is just a complementary solution for very sensitive data, in the case it is necessary to store that on client side.

inf3rno
  • 24,976
  • 11
  • 115
  • 197

1 Answers1

2
  • If everything comes from a secure source and there is no way to run scripts from afar then you're safe from XSS anyway.

  • If someone gets to run scripts - that closure won't protect you at all. For example, people can override $.ajax in their scripts or even the XHR object itself. Closures do not form any way of protection from that sort of attack nor are they supposed to. (WebWorker s on the other hand are a possibility).

Generally - it's not worth the effort in you case. You can never trust the client if you let arbitrary scripts to run.

For the fun, and because I like coding - here is a simple proof of concept that steals an auth token in your scheme. Here is the result

(function externalCode() {
    var xhr = XMLHttpRequest;
    XMLHttpRequest = function () {
        var x = new xhr();
        setTimeout(function () {
            // for simplicity I assume it's done after 1 second
            console.log("Hijacked response", x.responseText);
        }, 1000);
        return x;
    };
})();
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • It is not possible to fake the XHR because you can check whether it is native function or not: http://ajaxian.com/archives/building-an-isnative-method The problem is with the external libraries, because they don't use dependency injection, they just pull in their dependencies from global namespace. For example document, window, xhr, etc... If I cannot inject those params, I cannot protect them... – inf3rno Nov 20 '13 at 07:01
  • WebWorkers does not help in this case, they cannot reach DOM, and maybe the injected code would run in their scope, I don't know. – inf3rno Nov 20 '13 at 07:04
  • @inf3rno web workers give you the ability to isolate code - not touching DOM is a part of that. Now let me see if I can bypass that native method checker for the sport :) – Benjamin Gruenbaum Nov 20 '13 at 07:05
  • That isNative method doesn't work here (Chrome latest), it returns false for the _native_ `XMLHttpRequest`. Even if it did, it's not useful for detecting malice (I can of course just override my method's toString and bypass that, if you call Function.prototype.toString on my function - well I can just override that too :) Attackers can get really creative and I wouldn't dare count on these sort of tricks for security. – Benjamin Gruenbaum Nov 20 '13 at 07:08
  • 1
    @inf3rno and of course, the _real_ answer is CSP (content security policy). That is designed exactly to prevent these sort of attacks (although sadly it doesn't mitigate extensions/addons for example). CSP is awesome but the problem is CSP is not widely supported. – Benjamin Gruenbaum Nov 20 '13 at 07:10
  • 1
    @inf3rno the link you've given actually explains that you cannot check weather a function is native or not. what it does is that it checks if some things are in place when a new object is created, but that's different thing than checking from existing xhr function if it is the original one or mangled one. – eis Nov 20 '13 at 07:10
  • Ahm. In most browsers the toString or toSource methods returns "native" or something like this by native functions. You can secure those methods too with closures. But I think you are right. It is really hard to think about every external variable and protect all of them... For example by the edited question in my code at first I forgot protected the `console.log`... And that was just a simple script... – inf3rno Nov 20 '13 at 07:26
  • Okay, thanks, I accept this as a solution, it is really hard to protect everything, and it does not worth the effort... – inf3rno Nov 20 '13 at 07:27
  • 1
    I'm glad I helped. Fun fact - you can still "steal" console.log in your code, here's one way - http://jsfiddle.net/9Ne7Q/ . There is really no alternative right now, let's just hope that when CSP kicks in our lives will get a lot easier :) – Benjamin Gruenbaum Nov 20 '13 at 07:34
  • Ahahaha, I have not thought on `Function.call` :D :D :D Ye thanks, this is really funny :D – inf3rno Nov 20 '13 at 07:41
  • And we still have not thought on every possibility, for example object setters and array constructors... http://stackoverflow.com/questions/3146798/why-do-people-put-code-like-throw-1-dont-be-evil-and-for-in-front-of – inf3rno Nov 20 '13 at 08:26