Take the 2-minute tour ×
Information Security Stack Exchange is a question and answer site for Information security professionals. It's 100% free, no registration required.

My application is running an API authentication that uses tokens rather than cookies.

This leads me to ask a few questions :

  • What is the most secure way to store the token ?

By using random tokens you eliminate the issue of CSRF attacks but on the other side there are no Secure and HTTPOnly flags.

I thought of maybe using some kind of trick using the new ECMAScript Harmony Object.freeze() and Object.seal() features but this seems to be more of a hack than something that would be secure.

  • How should I authenticate WebSocket clients like Socket.io on top of HTTPS ?

Most libraries like Socket.io, ws, Sockjs and Faye don't allow to set custom HTTP headers or it's not compatible with the various fallback protocols like Flash sockets.

One possibility would be to send the token as part of the handshake in the URL's query arguments but I don't really like it because it means that :

1) - Tokens will be shown in logs files that log only the URL

2) - I would have to authenticate first during the handshake and then every time I send data which would mean two separate systems.

That's just on top of my head by thinking a little bit about it. There might be some more underlying issues.

  • Am I just too paranoid and this option is actually secure ?

I could also implement some kind of asymmetric scheme using a public / private key system, but this seems just to error prone / complicated to be a reliable solution.

My final question is more of a consequence of the questions above :

  • Is the trade-off of having random tokens rather than cookies worth it ?

On one side you don't have CSRF attack vulnerabilities but on the other side you have a lot of other cases where the answers (for me at least) doesn't seem to be so clear-cut.

Thank you in advance !

share|improve this question

2 Answers 2

  • How should I authenticate WebSocket clients like Socket.io on top of HTTPS ?

There is no need to authenticate a connection more than once, so if you are using websockets, you can put security token in the first message that client sends after connecting to the service. HTTPS is a must. After handshake you will have secure connection (token can be sent). After sending security token (and receiving server response that confirms its validity) you will have authenticated connection.

  • What is the most secure way to store the token ?

The most secure method would be to use localStorage and make it inaccessible outside of your code (by keeping the token and localStorage object in scope of a closure).

function freezeProperty(obj, name, value) {
    Object.defineProperty(obj, name, {
        enumerable: false,
        configurable: false,
        set: function() { throw name + " property is frozen" },
        get: function() { return value }
    });
}

(function() {
    // function scoped
    var $token;
    var $storage = window.localStorage;

    // to make localStorage globally inaccessible
    // we assign fake localStorage to window object
    freezeProperty(Object.getPrototypeOf(window), 'localStorage', {});

    $token = $storage.token;

    if ($token != null) {
        // start communication
    } else {
        loginService.login(function(token) {
           $storage.token = $token = token;
           // start communication
        });
    }
})();
  • Am I just too paranoid and this option is actually secure ?
  • Is the trade-off of having random tokens rather than cookies worth it ?

It depends on requirements regarding security. Websockets can increase security if you allow only one connection per user session and block the possibility of using your socket from outside of your code (again by using closures). This way, even if attacker is able to execute JS, he will not do much harm.

You may also be interested in freezing prototype of window object,

function freezePrototype(obj) {
    freezeProperty(obj, '__proto__', obj.__proto__);
    Object.freeze(Object.getPrototypeOf(obj));
}

freezePrototype(window);

disabling ability to open new windows,

freezeProperty(window, 'open', undefined);

or disabling some event listeners (after settings yours).

function disableSettingListener(obj, eventType) {
    freezeProperty(obj, "on"+ eventType, undefined);
    var original = obj.addEventListener;
    function decorated(event, listener, bubble) {
        if (event == eventType) return;
        original(event, listener, bubble);
    }
    freezeProperty(obj, 'addEventListener', decorated);
}

disableSettingListener(window, 'unload');

If user's machine is compromised (malicious browser extension, or cracked browser, or attacker with admin privileges), all above will not make any difference (attacker will be able to steal the token).

Don't know if all the code I posted here work in browsers other than firefox (I believe it's ecmascript5-compliant).

Resources:

share|improve this answer
    
Interesting... did you come up with this yourself, or is this from online resources? I'd be interested in any links you have with further information. –  paj28 Apr 16 at 8:24
    
I came up with security implications of JS meta-object protocol. The rest can be found on the web (I've added some resources to my answer). –  Maciej Chałapuk Apr 16 at 12:03

To store the token:

  • For a traditional (non-Ajax) web app you usually store the token in a hidden form field.

  • For a single page app you usually store the token in a JavaScript variable and include it in the JSON data with each request.

This approach avoids the token being in the URL, and it works with WebSockets.

Most applications use a cookie as the main session ID, and have a second token which is purely to prevent CSRF. You can ditch the cookie and solely use the token, as you suggest, but doing this is not standard practice, so you should only do it if you're sure you know what you're doing.

As you mention, cookies have an HttpOnly option that is not possible with tokens. Although tokens don't have a secure flag as such, that is less important, as you can adjust your code so the token is only ever sent over SSL.

One other thing to be aware of is you can now prevent CSRF without using tokens, primarily using the origin header. However, most sites still use tokens.

You can do normal cookie authentication with WebSockets. This question has some information. I don't know what the CSRF implications of this are.

share|improve this answer
    
I'm talking about tokens that are used like cookie replacements, so no CSRF tokens. I want to not use cookies as it is often a security issue and the solutions that exist like CSRF tokens often have implementation issues. Also hidden form fields often imply server-side rendering which is not necessarily the case. Also storing the token itself in a variable is an issue since you loose persistence. –  Awake Zoldiek Apr 8 at 13:25
    
@AwakeZoldiek - do you have a specific application in mind, or is this a general question? If there's a specific app, more details would help. If it's a general question, I doubt you will find anything that is better than cookies. You could use HTML 5 web storage, but there's no strong reason to prefer this over cookies. Your thinking that "cookies are often a security issue" is misguided. Anything can be a security issue if done badly. Cookies are ok in principle, you just need to take care to use them correctly. –  paj28 Apr 8 at 14:25
    
Well here's my reasoning (correct me if I'm wrong !): In my opinion as a developer, I can eliminate a whole class of attacks (CSRF) easily if I don't use cookies. On top of that if I did want to use cookie, CSRF seems to be hard to implement and error prone. Even big companies like Twitter had issues with their CSRF tokens. At the moment I store tokens in the localStorage if the "remember me" option is ticked otherwise I use the sessionStorage. I might be completely wrong, but this is just how I feel about the situation as a developer. –  Awake Zoldiek Apr 8 at 14:41
    
Saying you eliminate CSRF by not using cookies is like saying you eliminate SQL injection by not using a database, cookies are needed to exploit CSRF but they are not the cause of it. In my opinion you should use both cookies and token, because they are 2 different layers of protection. A cookie will make sure your session is valid and a token will make sure the request was intended by the client. By using only a token, IF somehow your implementation is flawed and an attacker somehow gets a valid token, he could do anything. This is not the case if he has the token but not the session –  Kotzu Apr 8 at 15:05
    
@AwakeZoldiek - CSRF protection is not particularly difficult to get right. If you can't get it right, I expect you will have other security problems with your app, such as cross-site scripting. Most major websites do have security issues from time to time, just like Twitter. This is why the standard approach is cookies + anti-CSRF tokens. –  paj28 Apr 8 at 15:08

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.