Suppose we have a big JSON document that only certain users can see, but that rarely changes, but which, if it does change, users expect to see the change quite quickly. It makes sense to use etags for this - it saves the whole document being transferred over the wire if it didn't change, yet sends the document if it has.

One risk seems to be that if multiple people use the same browser window:

  • Alice signs into the site, and the resource is sent to her with an etag
  • Alice signs out and goes to get lunch
  • Bob users her browser to sign in as himself - but he can't view the resource
  • Bob looks in the browser cache, sees an etag that was stored by the browser, and configures his browser to send that same etag - now Bob can see the data

I suppose that since Bob is already using Alice's browser instance, he could already see what's in the cache and therefore could read the data anyway.

It seems there is no safe way to use etags (or browser caching in general?) for sensitive information, and we should just store the data in memory with JavaScript. Or are we missing a specific way that it's meant to be used?

  • Server-side encryption of the etag using a hash of the client-side+server-side session tokens as a key? If your session expires on sign-out? – Οurous Apr 12 '17 at 6:36
  • The etag check is done on the server, that still allows you to authenticate the request prior to the etag check. The above would only be true if you were using etags on the CDN because it's not validating at your side. – Phill Apr 12 '17 at 6:45
  • But the data is still in the browser cache. Seems like caching anything sensitive using any caching header has this risk if someone can access the browser cache? – Paul Stovell Apr 12 '17 at 6:52
  • Sure if the user has access to the machine then it's stored in the browsers cache. But the browser wont load from the cache if you don't return a not-modified header. If you validate the request and return not-authorized then he can't view it unless it specifically looks for it in the cache. You could encrypt the data and decrypt it and store the key temporarily for in the session storage. Then even if he does find it he can't use it. – Phill Apr 12 '17 at 6:54

Using the etag to get the data

Knowing the etag alone will not help you with getting the secret resrource, assuming the server is properly implemented. The browser will check with the server to see if the etag is valid (using the If-None-Match header).

When Alice makes the request, she will be authenticated so the server should respond with 304 Not Modified, prompting the browser to load the resource from the cache.

But when Bob makes the request he is not authenticated, so the server should respond with 403 Forbidden. The browser will then not load anything from the cache (and if Bob is using a different browser than Alice, there wouldn't be anything to load anyway).

All this rests on the assumption that Cache-Control is set to no-cache (or absent). If not, the browser would load the resource directly from the cache without checking with the server. If Bob and Alice are using the same browser Bob would then get Alice version of the page, even though he is not authenticated.

Stealing the resource from the browser cache

As you point out, instead of just stealing the etag Bob could simply steal the actual resource from the cache.

Modern browsers protect against this in various ways. Unless Alice and Bob are using the same OS user or Bob is root or admin (depending on the OS) this could not be done without leveraging some exploit.

Still, if the resource is really sensitive and you expect your users to access it on computers that are shared with non trustworthy people, you should consider setting Cache-Control: no-store disabling all cache.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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