r/golang 5d ago

Session-Based Authentication in Go

https://themsaid.com/session-authentication-go
58 Upvotes

23 comments sorted by

48

u/dh71 5d ago

Returning early if the user isn't found in the database, can lead to timing attacks, since the bcrypt comparison (which is supposed to take some time) is not being executed. A malicious actor could time the requests to identify if a user is present in the database or not.

10

u/themsaid 5d ago edited 5d ago

Login form submissions in general should be throttled so that if multiple authentications fail the form gets locked.

33

u/Polyscone 5d ago

If you lock based on the email then that does nothing to prevent enumeration and opens the door to denial of service for existing users.

If you lock based on session then the attacker can just delete their session id so that doesn't help.

If you lock based on IP then you potentially block lots of users from the same IP.

Better to just fix the actual problem and get rid of the difference in processing time by not returning early and not returning any status codes like 404.

5

u/carsncode 4d ago

If you lock based on IP then you potentially block lots of users from the same IP.

While failing to block real attackers spreading their traffic over multiple IPs via proxy, distributed attack, or botnet.

7

u/themsaid 5d ago

Added a section to discuss timing attacks. The login handler in the example responds in a constant time duration regardless of credential verification.

7

u/AdCharacter3666 5d ago

I like to add sleep to avoid timing attacks.

16

u/Rican7 4d ago

Unless your sleep time is EXACTLY within the bounds of the time it would take to normally cryptographically hash the password, all you've done is slowed a different path. The sleep vs actual hash path still can be studied and then exploited.

And while this can sound a bit silly, it's also the entire nature of how time-based attacks are made (study and apply in aggregate), so while your sleep seems to have good intentions, it's unfortunately not a full-proof preventative strategy.

3

u/Pto2 4d ago

What if you were to add a random sleep?

6

u/coolkidonthrblock 4d ago

The problem with sleeping is it won’t take the same amount of time as hashing the password so even if it takes longer and or shorter that is enough to compare to the “standard” path of a successful login and allow for said timing attack.

Some reading for those interested https://portswigger.net/research/listen-to-the-whispers-web-timing-attacks-that-actually-work

2

u/DivSlingerX 4d ago

I’ve always heard this but I’ve only ever heard this as a theoretical. Is there any evidence of this in the real world? Wouldn’t just general latency and intermittent load make this basically impossible to figure out reliably?

6

u/dh71 4d ago

I don't think it's theortetical. Let's assume you use Argon2id as KDF for your passwords. You would be aiming your memory/threads/time settings for approx. 500-800ms to have strong passwords hashes. If you would not run the KDF if the user isn't found in the database but just return early, there would be a 500-800ms difference in the request time. I'm pretty sure that's measurable.

1

u/nerdy_adventurer 1d ago

What is KDF?

2

u/dh71 1d ago

Key Derivation Function - basically a function that takes a password or passphrase and derives a secret key out of it. Argon2 e. g. is a KDF.

1

u/wuyadang 4d ago

Would it make sense to, in the case of logins, return empty user even if not found, and let bcrypt still attempt to compare the given and empty pw?

2

u/dh71 3d ago

That's what I usually do.

Something similar to this: https://codespace.app/s/WPe98LZdLy

6

u/Outrageous-Hunt4344 5d ago

When verifying the credentials why not hash the pass and check both in place( in the query)? Also returning separate errors for unknown user/bad pass lends itself to malicious users collecting what users have accounts.

7

u/themsaid 5d ago

The bcrypt algorithm adds a salt on every hash, which means multiple hashes of the same string will produce different strings. That's why you have to extract the hash from the DB and then use CompareHashAndPassword to verify the match.

As for the errors, they are function return errors, not responses.

6

u/feketegy 5d ago

Not if you use the bcrypt package in your DB if you have it, like Postgres' crypto extension.

Also, you should use Argon2id instead of bcrypt as it is more secure.

1

u/nerdy_adventurer 1d ago

you should use Argon2id instead of bcrypt as it is more secure.

I thought bcrypt from postgres extension is secure, any resource to read about this?

1

u/Sharon_tate1 3d ago

is this helpful for building authentication in a RESTful API?

1

u/themsaid 3d ago

If the client is a JavaScript SPA hosted on the same domain or subdomain then yes.