5 ms·
Huh, I always forget a lot of programmers weren't around when this stuff was invented. It's all actually pretty simple, and very little complexity. However, the
by withinboredom 3y ago
Huh, I always forget a lot of programmers weren't around when this stuff was invented. It's all actually pretty simple, and very little complexity. However, there are so many "gotchas" (that can result in zero security) that anyone writing a guide like this would probably have you sign a waiver, then any company you work for sign a waiver, and include your firstborn child.
For example, user/pass is pretty simple on the surface:
1. app sends server user/password.
2. check if it matches the password in the database.
3. if so, respond with a token the app can send back that is associated with the user. if not, return with a 401.
The number of gotchas in this simple 3-step process is insane... here's some off the top of my head (not exhaustive):
- make sure the login form includes a CSRF token.
- do not store the password in plaintext in the db. or encrypted, probably. Since an attacker can possibly get the encryption key and then decrypt all your passwords. Use strong, slow hashes.
- rate limit your logins to prevent brute-forcing (slow hashes work great here)
- use constant-time comparisons to check if the password matches (e.g., hash_equals() in PHP), RTFM for whatever constant time check you are using or you will open yourself up to timing attacks.
That's the issue with security stuff, there are so many gotchas that anyone writing a course would open themselves up to getting sued (at least in the US) just for missing a gotcha or someone with Dunning-Kruger thinking they know everything and getting hacked ... it's too risky. You have to just get into the industry and learn it the hard way. At least that's how I learned everything I learned.
- vindex10 3y agoI would add: * on the client side, store the token as a secure https only cookie, as local storage is accessible by any module of your app, see supply-chain attacks. * be extra careful with oAuth [1] * for APIs, be strict with CORS [2] [1] https://salt.security/blog/oh-auth-abusing-oauth-to-take-over-millions-of-accounts https://salt.security/blog/oh-auth-abusing-oauth-to-take-ove... [2] https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
- hobo_mark 3y agoI'm having to deal with this stuff right now. Firebase stores their refresh token in local storage and that allows minting new session tokens once they expire, are they wrong? Is there any other way to remain signed in "forever"? (until logout or until token is revoked)
- vindex10 3y agoI didn't work with Firebase myself, isn't this something relevant? https://firebase.google.com/docs/auth/admin/manage-cookies https://firebase.google.com/docs/auth/admin/manage-cookies
- hobo_mark 3y agoThat is what I'm using but I have to authenticate again every few days. If I used the client library it would autorefresh the token periodically, but that stores the refresh token in local storage. Since that is something you recommend against, I was wondering why.
- vindex10 3y agoJust to be clear, I'm not a security expert in any way, just learned myself while building things. So here is what I'd refer to: https://stackoverflow.com/questions/44133536/is-it-safe-to-store-a-jwt-in-localstorage-with-reactjs https://stackoverflow.com/questions/44133536/is-it-safe-to-s... Regarding the Firebase, I see an open issue on this, so I guess we are not the only ones wondering :) https://github.com/firebase/quickstart-nodejs/issues/194 https://github.com/firebase/quickstart-nodejs/issues/194
- jonasmerlin 3y agoActually, I think we're doing a huge disservice to our profession as programmers when we call stuff like this "an insane number of gotchas". This is no critique of you or your post specifically, mind you, and I know where you're coming from. But it's a critique of a general tendency among programmers to call anything that requires a bit of knowledge and thought beyond the simplest surface level solution "complex" or "insane to implement on your own". It's not. While I know that you're list of gotchas isn't exhaustive, the real list is not so much longer that it's not perfectly reasonable to expect someone to be able to implement it correctly. I say that as someone who was on the "receiving end" of this kind of advice for years btw. I always thought that the things that are "better left to libraries" are really arcane and impossible to understand, which only lead to confusion and an inability to truly assess options. And it's really just a matter of semantics and framing. It would be perfectly reasonable to say "it's not complex as long as you keep this reasonably long list of gotchas in mind".
- withinboredom 3y agoI don't know why you're getting downvoted (I have no idea why people are on HN if they think this is just Reddit. If you downvote, say why and start a discussion), but you're right. My intent wasn't to imply "just don't do it" or "leave it to libraries." I was trying to say why you can't really find a guide like the post is asking for (at least for free!) and it likely has a lot to do with liability and things like that. I was trying to say exactly what you are saying, and that is just get in there and learn. It isn't that complex to implement this stuff yourself if you need to. I've implemented this stuff myself dozens of times over the years... but I try to use a library before implementing it myself. Interestingly, over the years, I've reviewed libraries and found bugs in them. So, do read the code of the library you're using. Once you've reviewed a few of them (and implemented it yourself a few times), you kinda get an idea of what to look for.
- jonasmerlin 3y agoHaha, thanks for your reply and for understanding where I'm coming from. And while your original comment might not be a _direct_ reply to OPs question, I would've hoped for it to be far more upvoted as well, as it's easily one of the most valuable comments in this thread in my opinion. HN truly is weird sometimes. The only thing I took issue with in your original comment was the "The number of gotchas in this simple 3-step process is insane" and the "there are so many gotchas" parts, as I think that this exact wording made me read the whole thing in a wrong way. I just wish we would tell people new to these kinds of topics "Don't fear this, this is normal, but totally manageable! It might seem like a minefield at first, but actually, there's a very well-trodden path through it. Here's (part of) the map." (Basically,you provided that map, which is great, and more than people genrally do, but the wording above made the map seem more daunting than I would wish.)
- Jach 3y ago> slow hashes work great here Also... don't rely on slow hashes themselves for rate limiting. They're slow because they eat up CPU. Rate limit the requests themselves or you're setting yourself up for denial of service fun. (And also, slow for your server does not necessarily mean prohibitively slow for an attacker's cluster if they do manage to dump your DB. Salting is useful and hopefully uniquely done per account for you by your hashing function, but it's also useful to just forbid very weak passwords entirely, and maybe go so far as to forbid even strong-looking ones that have shown up in data leaks.)
- withinboredom 3y ago[extremely popular framework] doesn’t do salting per account. Imagine my surprise when I could simply copy my user’s password field to another user in the db and login with my password as them. Luckily it is super pluggable so we could implement proper salting. It’s entertaining how even popular frameworks can miss simple gotchas.
- projektfu 3y agoCould you copy your password and the per-user salt and get the same result? Or does it also concatenate the username? Edit: just honestly curious, how to implement it best.
- withinboredom 3y agoThe best thing is to use a salt that is a fact about the user that can’t reasonably change (like the user ID). So you can copy the password field, but if you copy the user id too then nothing happens (assuming there isn’t a unique constraint in the db), you are still logged in with the same user id. However, user ids really only work for UUIDs as numbers are not random (and very easy to create rainbow tables for). If your users can’t change their user name or email address, you could use that as well.
- projektfu 3y ago