[erlang-questions] web authentication

Frédéric Trottier-Hébert fred.hebert@REDACTED
Thu Jul 7 22:04:58 CEST 2011

The digest authentication you see at this point is something that's part of the HTTP protocol. It is technically unrelated to your application (although your application can see it through HTTP values) and the client-side of it is implemented by the browser.

I would consider it highly impractical for how little control it gives you (even in terms of visual design) and in general security. The browser being in charge of it means the session handling is annoying (no way to disconnect, the browser just resubmits the data all the time for you, proxies become tedious, etc.)

If you're okay for a longer read, here's what I know, in condensed format. Others can feel free to correct me.

Modern authentication schemes usually work a bit that way

i. The user registers to the website on an HTTPS page (so that the password being sent isn't observable by third parties)

ii. The password is stored in a database after being hashed by bcrypt or scrypt with a convenient, but slow work factor as to make brute-force (if the DB is compromised) absolutely impractical. These algorithms store their own difficulty factor, so that if you want to up the complexity, it can be done quite simply even if you have many versions in the DB.

iii. Avoid using MD5 or SHA-x hashing functions. MD5 is collision-prone, some of the SHA functions too. MD5 and SHA hashing functions were made to be really fast and we want to avoid that. The reason is that it makes it easier to brute-force passwords if the table is compromised. Protect your users first. Bcrypt and Scrypt, by comparison, will salt the passwords for you and give each of them a work factor. If you take 100 millisecond to check a password (something that happens once per session, so it's fine to be slow) compared to 10 microseconds, it becomes a real pain for crackers to do their thing. During that time, you can warn your users to change their passwords in other services.

iv. bcrypt and scrypt handle salting for you, as mentioned before. If you decided not to use them, do remember to salt your passwords to avoid easier rainbow table attacks. Do NOT reapply a hash function many times over a previous hash results. Because all hash functions have collisions, this means that as you go, you increase the chances of collisions. Re-salt at each iteration. Again, if you use bcrypt or scrypt, this is handled for you and you do not have to worry. Please use bcrypt or scrypt.

v. If that wasn't obvious, use the hashing function of bcrypt, not the encryption that can be decrypted. You do NOT want to use encryption, but hashing. The reason is simple. If your system is compromised, you have to assume that your keys are also compromised. Encryption is unsafe for passwords. Hashing is the king.

That being said, the actual steps of authentication then become:

1. The login page is an HTTPS page so that the password that will be sent isn't observable by third parties
2. The user enters his own password, submits it
3. The server hashes it through the same hashing function used when first saving the password
4. Compare the two hash values. Note: you want this to be done in O(n) time so that it's impossible to know whether you get partial matches or not. This makes more sense for clear text passwords, but what the hell.
4.a if they're different, the authentication failed
4.b if they're the same, go to 5.
5. Create some kind of session value in another table or wherever you want. The session will have a key that you can choose randomly (UUIDv4 + userid to avoid duplicates although the chances are minimal, as an example).
6. Put the value in a cookie. You want that cookie to be set with the option HttpOnly to avoid having client-side javascript able to read it. Also give a reasonable timeout value to the cookie so the user has to re-authenticate from time to time. This means both server-time timeouts and client-side timeouts.

When a user loads a page, check the session cookie you defined, and match its value to whatever you've got in your session table. If it matches, the user has an active session. If it doesn't, have the user authenticate again.

Note that this scheme (and pretty much any other) is insecure against 3rd parties listening to the communications between you and the server. To solve this, move everything to HTTPS, although this is harder to optimise for performance.

Further considerations:

A. Put a limit on how many times someone can try to log in. You can have their account locked for a few minutes in between each time. This is to keep people from trying to brute force accounts from the outside.

B. HTTP cookies alone are not sufficient to know whether someone is authenticated or not. A specific kind of attack, named Cross-Site Request Forgery (CSRF) works by having someone doing an HTTP request for you, from a different domain. In these cases, the browser will automatically send the cookies along with the request (it can also be a javascript form that's auto-submitted). I've used this in the past to have a site administrator (a co-worker) close his own account without him noticing it. Woops.

This means we need an external value, not coming from HTTP headers to make sure the request is good.

In simple cases, you can try to check the referrer and make sure it's coming from your domain. However, flash components or HTTPS connections do not always have these settings, and if you have any of these pages on your site (and you will, if you do HTTPS authentication), you'll have to look somewhere else.

The safe way to do requires a few elements:

1. Never do changes with GET requests. GET is idempotent and free of side effects

2. Do your changes with POST. This will require a user to use either a) Javascript, b) curl, wget or some other tool or c) an HTML form to send your data. This restricts the window of opportunity of malevolent users, who can no longer just post a link or an image to do CSRF.

3. This is the most important point, use something called a token. This token is a special value that is added to whatever form you generate. When the user sends a POST query (or anything requiring server-side changes) to you, check that the token is there and that it is valid. The best tokens will have a one-time use, but they're fairly impractical when many different queries can be done without refreshing a page. My favourite way to handle these otherwise is to create different tokens for different namespaces. The admin panel will have its own token, the chat system its own token, the user settings will also have its own, etc.

The tokens have to time out at some point to make sure that someone who steals them can not damage the account for too long. Pick between a few seconds to a few hours based on how long you expect your user to stay on a single page.

4. Ask for the user password when changing vital information, such as the e-mail attached to the account, the password itself, buying an item, etc.

C. Never roll out your own encryption schemes or hash functions. Let mathematicians specialised in cryptography do their thing.


That should be about it for a quick guide. There are more complex issues to tackle for good authentication and security of user data, but as a basic intro, this should be okay. I hope this is helpful.

Fred Hébert

On 2011-07-07, at 15:29 PM, Joe Armstrong wrote:

> Slightly off topic. But I want to make an erlang web site.
> 1) How does web authentication work?
> Let's assume something like:
>   http://en.wikipedia.org/wiki/Digest_access_authentication
> This is easy to understand.
> What I don't understand is what happens if the session socket is closed.
> Handshaking tales place over an open socket and the client is
> authenticated - this
> is easy to understand.
> What happens if the socket is closed, and reopened in a subsequent request?
> Does the server set and receive a session cookie? Does the client remember and
> replay the authentication protocol?
> How does this work?
> 2) I want to make a web thing that requires the user to authenticate themself.
> Should I:
>    a) Roll my own (some MD5 + cookies should do the job)
>    b) Implement  http://en.wikipedia.org/wiki/Digest_access_authentication
>    c) Something else?
> Seems like for a real web site there is a lot of cruft involved
> preventing spammers,
> false-accounts, forgotten-passwords etc. can I get all of this for
> free by getting
> authentication credentials via goole/facebook or something? Is this
> what OpenID does?
> Finally is this entire authentication-user management-forgot my
> password built-in
> to any of the popular erlang web servers?
> Cheers
> /Joe
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions

More information about the erlang-questions mailing list