7

Whenever the topic comes up, almost every source recommends to never store authentication tokens in a place where they can be accessed by client-side Javascript. The recommendation is almost always to store them in an http-only cookie to protect them.

My interpretation of this advice is that this is meant to limit the damage XSS attacks could cause as the http-only cookie wouldn't be accessible from JS. The part I never see addressed though is if and how the ability to set strong Content Security Policies changes the risk calculation here.

If I start a new application and set a strong CSP that prohibits all JS except the one I bundle with my app, XSS attacks should be essentially impossible in all non-ancient browsers (and a modern JS app wouldn't run in the ancient ones anyway). And cookies add other potential security issues like CSRF, though there are also modern security features to mitigate those.

Assuming that you set a strong Content Security Policy, is there still a security advantage of storing credentials/sessions in cookies over local storage?

1

3 Answers 3

12

... prohibits all JS except the one I bundle my app, XSS attacks should be essentially impossible

This assumes that your (trusted) JS is free from exploitable bugs.

... is there still a security advantage of storing credentials/sessions in cookies over local storage?

The difference is between "not accessible by an attacker assuming there are no bugs in the JS" vs. "not accessible by an attacker because the browser prevents access from JS by design".

9
  • On the same note as with JS you should probably add to the last sentence "assuming there are no bugs in the browser"
    – Rsf
    Dec 29, 2023 at 11:50
  • @Rsf a browser bug could compromise the httpOnly cookie as well. Dec 29, 2023 at 12:26
  • 3
    @Rsf: For this purpose exploitable bugs in an application specific JS are way more likely than bugs in a wildly used browser. And more generic bugs in the browser also affect the security of the JS, even if the JS itself is not buggy. But of course, there might be bugs in the browser, in the OS, in the hardware ... Dec 29, 2023 at 12:40
  • To be fair, reported XSS vulnerabilities have been way way way down nowadays compared to even just 5 years ago. From frameworks, to browser support for things like Trusted Types... there is a reason why XSS was dropped (merged away) from the OWASP top 10. Like what I am saying is that with a modern framework with modern development approaches (CSP, Trusted Types) we have gone from 'by default code is exploitable' to 'by default code is secure from XSS'. Doesn't of course mean you might f*** up anyway, but "XSS should be essentially impossilbe" isn't far from the truth. Dec 29, 2023 at 13:41
  • 2
    @DavidMulder: that's one way to read OWASP top 10. The other is that XSS is no longer that special kind of injection to be mentioned separately, but that the other ones are also important (command injection, sql injection, ...). And also that one had to make some place for the new types of vulnerabilities in the top 10. And still being within the top 3 (as part of injection) isn't that reassuring either. Dec 29, 2023 at 13:49
6

I would not place that much trust in CSP to be honest.

I'm currently trying to tighten the CSP headers on a reasonably complex project. Some issues I'd worry about:

  • Third party components may require permissive CSP headers. In our case, some require unsafe-eval or wasm-unsafe-eval. Yes, we're working on fixing this, or replacing the offending third-party components, but that's non-trivial.
  • A typo in the CSP headers may completely disable CSP and the protection it offers. With complex CSP configuration (ours is over 800 characters), such a typo is easier to make than you think.
  • Compounding the previous issue: browsers have inconsistencies in their CSP implementations. Particularly in how they deal with directives that are out of spec, and in how they do reporting.
  • A webserver misconfiguration, or wayward proxy may cause the headers to disappear completely, and you may not notice this for a long time.

If you do rely on CSP that much, you'd better test that it actually works as intended. That is, have a test case for every directive you care about, and actually test it frequently in every browser you care about.

You may also find Lessons learned from publishing a Content Security Policy by Matteo Mazzarolo an interesting read. He talks mainly about browser inconsistencies and CSP reporting struggles, but it offers good insights in the large number of subtle issues.

All in all, I've come to consider CSP a nice extra layer of security for web applications, but I'd never consider it a first line of defense.

1
  • > All in all, I've come to consider CSP a nice extra layer of security for web applications, but I'd never consider it a first line of defense. The same can be said for most aspects of a good security program... A layered defense is the best way to make sure that a hole in one area will (hopefully) be covered by another.
    – jcasner
    Apr 25 at 16:51
4

Assuming that you set a strong Content Security Policy, is there still a security advantage of storing credentials/sessions in cookies over local storage?

The advantage isn't that significant to begin with([1]) & the concept of a strong CSP can quickly become shaky([2]).

Assuming you have a very simple and strong CSP which truly prevents all XSS issues, then local storage and httponly cookie should be equivalent.

Both are merely defense in depth measures. I you want both benefits, implement both if your application allows it. If it requires local storage, I wouldn't consider it an issue though.

Regarding CSRF, you can set your cookies to samesite=strict to mitigate that (ideally in addition to your actual CSRF protection).

[1] (little) advantage of httponly cookie over local storage

almost every source recommends to never store authentication tokens in a place where they can be accessed by client-side Javascript. The recommendation is almost always to store them in an http-only cookie to protect them.

Defense in depth is great. But really, when there's an XSS issue, the victim is fully compromised either way.

If you can't read out the session cookie, you can still read out any/all data the victim can read & perform any action they can perform. You don't need the session cookie for that & you couldn't do more with it than without. Having it is merely a convenience, not a necessity.

Now, in a real-world attack, convenience isn't nothing. It might deter novice attackers. But a determined attacker will not be limited.

The above is assuming a standard XSS issue. Sometimes there are limitations on allowed characters or length of a payload, where stealing the session token is the easiest (or even only) sensible way to exploit. But in my experience, that's rare.

[2] strong CSP?

If I start a new application and set a strong CSP that prohibits all JS except the one I bundle with my app, XSS attacks should be essentially impossible in all non-ancient browsers

That should be the case.

A strong CSP is relatively easy to do if you build your JS around it from the ground up (and your libraries allow it). If you have a legacy app or rely on a lot of libraries / cdns, the many exceptions you may need to add quickly make it very difficult.

Even something like script-src 'self' can cause you problems if you eg have JSONP endpoints, file uploads, etc. And of course unsafe-eval - required by many libraries - can easily break your CSP.

Still, a CSP is great defense in depth. Your security shouldn't rely on it though, and except for very simple apps, determining if your CSP is strong is non-trivial.

You must log in to answer this question.

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