3

I'm building a JSON API. For authentication I plan to use a random-token based approach, with the random token having 256 bits of entropy and generated using a CSRNG. A hash of the token will be stored in server-side in the database. For most clients, I will send the authentication token to them in an Authorization header. All communction will be over HTTPS.

The general pattern that I plan to implement is described in the first part of this SO answer.

My question is about clients of the API which happen to be single-page-applications running in a web browser. My understanding is that it is not safe for them to store the authentication token in local storage or in memory due to the risk of XSS attacks and compromised JavaScript dependencies. It's also not safe to have them store the authentication token in a HttpOnly cookie due to the risk of CRSF.

The solution seems to be to send the authentication token to the client in a HttpOnly cookie, AND also implement a Synchronizer Token Pattern where we generate an additional token that is sent to the client in a header when they first authenticate. The client can store this additional token in local storage, and pass it back to the API in a header with subsequent requests.

Reasonable enough. But what I would like to understand is whether there is any risk in not generating a new additional token to implement the Synchronizer Token Pattern, and instead just splitting the original 256-bit authentication token so that the client receives half of it in a HttpOnly cookie, and half of it in an header that they can keep in local storage? The API server then reconstructs the full authentication token when receiving the request.

Granted, if one of the halves was exposed, there would only be 128-bits of entropy remaining for an attacker to guess (but I think that is probably still sufficiently difficult).

Otherwise, does this achieve essentially the same thing from a security point of view? Are there any subtleties that I'm missing here?

2
  • you can store something in memory in JS, and use it, without any other scripts having access to it. all you need to do is control the reference to the variable, often via a wrapping function that knows the token and anything can call, but nothing can introspect or alter. Without storage, you have to re-auth if the page gets reloaded.
    – dandavis
    Jun 17, 2019 at 17:00
  • @dandavis Thanks, that's really interesting. I'm not a really a JS developer, and the fact it's possible is new to me. Do you know of any examples you could point me in the direction of? Jun 17, 2019 at 19:17

1 Answer 1

1

Here's the simplest example possible to show how to store values securely in JS code:

var api = (function(){

    let secret = prompt("enter a secret phrase"); // Only the api object can reach this

    return { // a method to compare guesses to the secret
     auth: phrase=> phrase == secret
    };

}()); // end privacy wrapper

// test it in console by entering bingo at the prompt:
[api.auth("one"), api.auth("bingo"), api.auth("cheese")];
// evaluates as [false, true, false]

In a real application, the secret is fetch()ed by ajax, a cookie, or whatever else you use. The crux is just that the only access to the secret is via the methods defined within the wrapping function that defines the "private" variable. This pattern is called a "privileged method" in JS, being made available to code outside only through the terms and conditions that your "api" object stipulates.

1
  • While the secret value is "private" in that it cannot be accessed by outside code, if it exists hard-coded in the JS, a simple examination of the source code will reveal the secret value. If the secret value is fetched by an AJAX call, examination of network calls in the browser would reveal the secret. I don't believe it is possible to securely store secrets client-side.
    – shimizu
    Oct 4, 2020 at 20:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .