Mark Tie

Developing an Authentication System

Not a Plaintext Password Offender
Published on
Authors
  • avatar
    Name
    Mark Tai

Once I had wet my feet into databases with the game server for T9, I knew that I wanted to have a more sophisiticated user system. I have always been interested in network security and the battle of white hat and black hat, but I never implemented my own user authentication system. I knew from just random security articles that a password should always be hashed and salted before touching a disk, but things like OAuth went over my head.

I decided to work with something simple that I understood from top to bottom. In my current implementation, I use bcrypt to salt and hash passwords, which is then stored in a database with user name and user ID. When a user requests to log in, a secret is generated using the crypto/rand Go package and used for the next 30 minutes. Future requests need to use this secret to be authorized. For these authorized requests, I use HMAC to generate a signature. The time and path are concatenated and used as the message, whereas the generated secret is converted into base64 and then used as text for the secret. The time sent and the HMAC are put into the request headers. If the time sent is too old by the time it reaches the server, then the request is rejected. Then the server generates an HMAC to compare against the request's.

When testing the HMAC generation, I had a funny problem. Go uses bytes as an argument to generate HMAC, whereas online generators used strings. I assumed that the strings were parsed as hexadecimal, but they were converted from their ASCII values. For the longest time, I wasn't able to create matching HMAC's. I ended up using the ASCII value of the base64 encoding of the random bytes that I generate as a secret. Although a bit hacky, it has all the entropy of using the random bytes directly as well as nullifying the need to convert things to bytes in the client.

I realized a little later that the HMAC portion of the authentication was nearly unnecessary, as I already trust HTTPS with the client's password. However, in the off chance that the messages can be sniffed after the initial log in, a man in the middle would be unable to determine the symmetrical secret. Even if it was excessive, using bcrypt and implementing HMAC was a lot of fun and got me more acquainted with all the in's and out's of HTTP requests, hashing, and byte encoding formats.

If you see any problems with the way I implemented my user authentication or just want to talk about network security, please send me a message at mark@marktai.com. I'd love to hear your feedback!