3

I'm implementing custom authentication & session management system in Node.js & PostgreSQL. My goal is to implement sessions that expire after 2 weeks (if not refreshed/renewed).

OWASP and other resources suggest to store unhashed session IDs both in database and cookie. However, if those session IDs are leaked from the database, then they can be used to successfully authenticate before they expire.

I wonder if hashing sessions would add some additional security against such situations. The implementation I'm thinking about would work like this:

  1. User authenticates.
  2. A session is saved to database with id (UUID v4) and token_hash (SHA256 hash of cryptographically secure random string).
  3. Both id and original unhashed token are saved to response session cookie(s).

Then on subsequent requests:

  1. Server reads id and token from request session cookies.
  2. If there's a session found with id, then the token is verified against token_hash. If it succeeds, then the user is authenticated.

(I'm thinking about using both session id and token/token_hash because I think it will be faster to first find the session simply using id, and only then verify token against token_hash. Otherwise, the token would need to be hashed on every request to find the session, which, I assume, would be slower, even if some fast hashing function like BLAKE3 would be used.)

  • I think this is actually a duplicate of https://security.stackexchange.com/questions/138389/should-i-also-hash-my-session-id-before-storing-it-in-the-database, which is in turn a duplicate of https://security.stackexchange.com/questions/136122/how-to-secure-store-sessions-values-in-webapps . Accepted answer is "Yes", second answer is "No, if you implement some advanced logic that makes it not necessary". – Alex Sep 27 '21 at 06:55
  • @Alex, these questions are indeed close, but my question is about specific implementation not mentioned in them. – Dominik Serafin Sep 27 '21 at 12:55
  • 1
    Why design a custom implementation when many proven and vetted methods (and library implementations) exist? – multithr3at3d Oct 02 '21 at 01:01
  • 1
    @multithr3at3d there can be many reasons, e.g. 1) greater control over implementation 2) needs not supported by existing solutions 3) actually creating/maintaining those 3rd party solutions 4) learning 5) curiosity – Dominik Serafin Oct 03 '21 at 03:02
  • 1
    If your database leaks, you have bigger problems than someone using the tokens. – ThoriumBR Oct 27 '21 at 20:56
  • @ThoriumBR with that attitude, why even hash the passwords then? – Dominik Serafin Oct 28 '21 at 18:47
  • @DominikSerafin sessions are transient, passwords aren't. Sessions are random, passwords usually aren't. Sessions aren't reused, passwords are. You can revoke all sessions and your users can log back in. You cannot do the same with passwords. If you hash the passwords, the database leak will take a while to crack all passwords, unless you use plain MD5. – ThoriumBR Oct 28 '21 at 22:24
  • And I believe "learning and curiosity" are the only valid reasons for implementing a session management from scratch... – ThoriumBR Oct 28 '21 at 22:25
  • @ThoriumBR of course, hashed passwords should take priority over hashed sessions. However, my point was that if passwords were unhashed, I'd still have bigger problems than that if my database leaks. You can always reset your user passwords, just as you can revoke sessions. ​So, following your logic, if I'll have bigger problems anyway, why should I even hash passwords? ― Password hashing is defense in depth, just as session hashing. The goal here is to minimize damage. – Dominik Serafin Oct 29 '21 at 12:32
  • 2
    I think you don't realize that hashing sessions have a performance cost that is paid on every request that uses the session token. A hashed password pays the cost only during login. – ThoriumBR Oct 29 '21 at 13:55
  • @ThoriumBR If you read my question again (especially the last line) you will see that the idea behind this specific implementation was with performance in mind. So, why do you think I don't realize about performance costs? Anyway, 1-2ms longer requests from SHA256 validation are a fine trade-off for me if it means enhanced security. – Dominik Serafin Nov 02 '21 at 20:35
  • It does not mean enhanced security at all. A random token is indistinguishable from an encrypted or hashed token. It can protect against a database leak, but on case of such event the damage is so high that protecting the tokens is futile. – ThoriumBR Nov 03 '21 at 01:19
  • @ThoriumBR if it adds a layer of protection after a database leak, then how is it not enhanced security? – Dominik Serafin Nov 03 '21 at 10:24
  • "It prevents your computer battery from exploding if a devastating fire consumes the entire building". It adds a layer of protection if a catastrophic event occurred, when that protection does not mean anything anymore. – ThoriumBR Nov 03 '21 at 10:51
  • @ThoriumBR then again, if database leak is be-all and end-all like you say, why even hash the passwords then? Hashing passwords doesn't protect from database leak as well, it's a layer of protection that is relevant only after the "catastrophic event occurred". – Dominik Serafin Nov 03 '21 at 11:16
  • 1
    the reason to save only the hashed password is because some users re-use logins. So if the database is leaked, you might compromise other accounts. (it also helps protect the actual password if you were using that as the "remember me" type cookie or session) Session tokens are nice because they can be revoked/changed without the user having to change their password. But a session is not really authentication and shouldn't be relied upon for sensitive actions (such as changing e-mail/password, making purchases, etc... require a relogin in those cases) – pcalkins Feb 24 '22 at 21:20
  • 3
    DB leaks are frequently read-only (lots of SQLi is limited this way, as are exposed backups or clone functions, etc.). If I gain R/O access to the SE DB and it's using hashed session tokens (or JWTs or similar), I can read everything that has been written - even if it's not visible to most users anymore - but that's it. Bad but hardly catastrophic for the users; most content on SE is public anyhow, especially to privileged users. If I gain R/O access to the DB and it's got unhashed session tokens in it, *I can hijack your session and post content under your name*. – CBHacking Feb 25 '22 at 11:53

3 Answers3

0

I think it will time consuming since you will validate id and token on each request. In my opinion, what you could do is implement stateless JWT authorization. Implement custom claims w.r.t to user ID in JWT token and set expiration time while generating the JWT token. It will minimize compute time of auth validation.

  • 1
    In terms of *compute* time, JWTs are almost strictly worse than server-stored random session tokens, even if the random tokens are hashed. JWT signature validation requires a minimum of two rounds of hashing (HMAC), or much much worse if asymmetric signatures are used. What JWTs avoid is the time to hit the DB or other storage. – CBHacking Feb 25 '22 at 11:44
0

To answer your question:
Yes, hashing the session ID does provide protection against the specific scenario that you are worried about. Storing and validating the hash on every request will indeed protect you against database leaks.

Considering the fact that your sessions are 2 weeks long, you can speed up the check for session ID by caching the data and then doing a DB lookup just for the hashed token. Similarly, you can have a different DB schema that can be used to speed up the query.

The comments are discussing how much you should care about this scenario. There are some valid comments but I'll leave that discussion to the comments section.

Limit
  • 3,236
  • 1
  • 16
  • 35
0

Sessions should be short

Sessions are generally short. The OWASP guidance for session length is:

  • 15 minutes for high security applications
  • 30 minutes for medium security applications
  • 1 hour for low security applications

It is also recommended that these sessions end when the user closes the browser, i.e. you should be using session cookie. Browsers know to delete these cookies when the browser is closed.

Given these constraints, storing the actual session IDs should not be an issue, as it is likely that any session IDs that are harvested by a hacker will no longer be of any use by the time they are used. That is why they are generally not hashed.

How to handle "long sessions"

That all being said, I see that you have a requirement that a user should be able to access the site again within two weeks without having to sign on again. This is a common kind of requirement, and is not usually supported literally (with a session that actually lasts two weeks). Instead, the session is allowed to expire, but the browser is issued a token which can be used to recreate the session when the user opens his browser again. For example, you could set a persistent cookie that contains the user's identifier and either encrypt it or sign it using a secret key known only to the server. You can also embed information that ties the token to the specific browser (e.g. IP address, user agent header, and browser fingerprint). And, of course, the token would include an expiration date (you should not rely on the expiration date of the cookie itself). The server validates the token and its signature and spins up a new session, restoring whatever state is necessary per requirements. To the end user, this is indistinguishable from a very long session.

If you do it this way, you do not need to do anything special to protect session Ids other than ensure they are cryptographically random and unique. Just protect (encrypt or sign) the persistent token.

John Wu
  • 9,181
  • 1
  • 29
  • 39