Creating a secure User model in Rails (Part 1)
February 27, 2009
While doing my third year project, one of the issues that has been perplexing me for about the last week is how to create a secure User model in Rails nowadays (version 2.2.2). In the good old days I used to do some magic and it worked, but then restful_authentication came along and everyone seemed to use that instead. Although it is a good plugin, it isn’t very apparent how it works behind the scenes. Rather than adding stuff to the model it stores everything in /lib on you add a require statement to the model. This works well to hide all the complicated stuff, but I want to know how it works! The other issue is that I am doing this via TDD (using Cucumber and Rspec), so need to write tests for this first – sounds fun eh?
Also it should be noted I am not working from scratch, I already have a restful authentication system, it just does User.find_by…, stores the passwords in plaintext, has no password confirmation when changing it, and lots of other really bad security issues! It also supports cookies for remembering, but I don’t feel this is particularly secure so I shall come back to that later.
Basic Design
Here is a basic design of what fields I want to end up with for my user model:
- Id
- Display Name (Text)
- Email (Text)
- Hashed Password (String, 40 chars)
- Salt (String, 40 chars)
- Cookie Key (String, 40 chars)
If you are not 100% familiar with the idea of a salt, rather than just hashing the password, you have the password combined with the salt. If someone gets access to your database it will make an attack a lot harder (in complexity terms, not difficulty terms), as they will need a new hash table for each salt. I am not convinced by them, because if someone gets hold of your database you seriously need to rethink security.
If you are familiar with hashing algorithms, you can probably guess I am using SHA1 (by the 40 character field length). Although it has known vulnerabilities (two different inputs can produce the same hash), this isn’t really an issue in this case, and is reduced as we are using a salt. The salt and cookie key are both generated randomly. The salt is regenerated whenever the password is changed, and the cookie key whenever the user logs in.
In the next post I will look at look at a few ways at creating a secure system, and in the post after that write the Rspec tests. Yes I know this isn’t TDD, but its rather difficult to write tests for something you don’t understand!