views:

1881

answers:

9

What is your preferred method/datatype for storing passwords in a database (preferably SQL Server 2005). The way I have been doing it in several of our applications is to first use the .NET encryption libraries and then store them in the database as binary(16). Is this the preferred method or should I be using a different datatype or allocating more space than 16?

+51  A: 

I store the salted hash equivalent of the password in the database and never the password itself, then always compare the hash to the generated one of what the user passed in.

It's too dangerous to ever store the literal password data anywhere. This makes recovery impossible, but when someone forgets or loses a password you can run through some checks and create a new password.

Quintin Robinson
@Quinton: That is pretty much what I do. With the .net encryption libraries it will hash up the password and then I pass that into the DB and store as a binary. I can only compare passwords by hashing user input and comparing it to what is stored.
TheTXI
It sounds like you are on the right track then.
Quintin Robinson
I recommend jbcrypt if you are working with java. Extremly simple to use
Jens Schauder
We store salted passwords too. In our case we convert the 160-bit has to base64, and store it in a varchar - it just makes things easier (strings are easier to read/write/look at). In addition to a global salt, we pre-salt with the the user's id (sid or guid), so that two users with the same password do not give the same hash. This makes dictionary attacks more difficult (more CPU cost), and prevents you from discovering the password for multiple at the same time, when everyone chooses the same password.
Ian Boyd
+11  A: 

I do the same thing you've described, except it is stored as a String. I Base64 encode the encrypted binary value. The amount of space to allocate depends on the encryption algorithm/cipher strength.

I think you are doing it right (given that you use a Salt).

Josh Stodola
+1 for addressing the real question here.
erickson
+18  A: 

THE preferred method: never store passwords in your DB. Only hashes thereof. Add salt to taste.

Assaf Lavie
mod up, had to do it, just for the salt joke ;)
Jakub
i grinned at it as well.
Ian Boyd
+6  A: 

Since the result of a hash function is a series of byte in the range 0 to 255 (or -128 to 127, depending the signed-ness of your 8-bit data type), storing it as a raw binary field makes the most sense, as it is the most compact representation and requires no additional encoding and decoding steps.

Some databases or drivers don't have great support for binary data types, or sometimes developers just aren't familiar enough with them to feel comfortable. In that case, using a binary-to-text encoding like Base-64 or Base-85, and storing the resulting text in a character field is acceptable.

The size of the field necessary is determined by the hash function that you use. MD5 always outputs 16 bytes, SHA-1 always outputs 20 bytes. Once you select a hash function, you are usually stuck with it, as changing requires a reset of all existing passwords. So, using a variable-size field doesn't buy you anything.


Regarding the "best" way to perform the hashing, I've tried to provide many answers to other SO questions on that topic:

erickson
If you read my question a little bit more closely, you'd see I am focused more along the actual storage in terms of datatype and space allocated for the field.
TheTXI
But +1 for providing extra information to others who may come along later.
TheTXI
Right on. It looks like I'm not the only one missing that ;)
erickson
+5  A: 
  1. store the hash of the salted-password, such as bcrypt(nounce+pwd). You may prefer bcrypt over SHA1 or MD5 because it can be tuned to be CPU-intensive, therefore making a brute force attack way longer.
  2. add a captcha to the login form after a few login errors (to avoid brute-force attacks)
  3. if your application has a "forgot my password" link, make sure it does not send the new password by email, but instead it should send a link to a (secured) page allowing the user to define a new password (possibly only after confirmation of some personal information, such as the user's birth date, for example). Also, if your application allows the user to define a new password, make sure you require the user to confirm the current password.
  4. and obviously, secure the login form (typically with HTTPS) and the servers themselves

With these measures, your user's passwords will be fairly well protected against:

  1. => offline dictionary attacks
  2. => live dictionary attacks
  3. => denial of service attacks
  4. => all sorts of attacks!
MiniQuark
All these measures can be quickly implemented and packs quite a punch for minimal effort! +1 =)
Luke Antins
+2  A: 

A simple hash of the password, or even (salt + password) is not generally adequate.

see:

http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes/

and

http://gom-jabbar.org/articles/2008/12/03/why-you-should-use-bcrypt-to-store-your-passwords

Both recommend the bcrypt algorithms. Free implementations can be found online for most popular languages.

finnw
Great links that go beyond the superficial security concerns. For deliberately slow algorithms, would it be important to have the hashes computed on the client side so as not to overload the (possibly already quite busy) server?
cheduardo
A: 

If you are working with ASP.Net you can use the built in membership API.

It supports many types of storage options, inlcuding; one way hash, two way encryption, md5 + salt. http://www.asp.net/learn/security for more info.

If you dont need anything too fancy, this is great for websites.

If you are not using ASP.Net here is a good link to a few articles from 4guys and codeproject

http://aspnet.4guysfromrolla.com/articles/081705-1.aspx http://aspnet.4guysfromrolla.com/articles/103002-1.aspx http://www.codeproject.com/KB/security/SimpleEncryption.aspx

Sruly
+2  A: 

I use the sha hash of the username, a guid in the web config, and the password, stored as a varchar(40). If they want to brute force / dictionary they'll need to hack the web server for the guid as well. The username breaks creating a rainbow table across the whole database if they do find the password. If a user wants to change their username, I just reset the password at the same time.

System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(
    username.ToLower().Trim(),
    ConfigurationManager.AppSettings("salt"),
    password
);
Shawn Simon
i used to use the username as added salt. But then we were unable to rename a user. We switched to using salt with is the users's id, guid, sid, or something other surrogate key.
Ian Boyd
tru, good call. this way you dont have to reset the password when you rename a user
Shawn Simon
+1  A: 

You can use multiple hashes in your database, it just requires a little bit of extra effort. It's well worth it though if you think there's the remotest chance you'll need to support additional formats in the future. I'll often use password entries like

{hashId}${salt}${hashed password}

where "hashId" is just some number I use internally to recognize that, e.g., I'm using SHA1 with a specific hash pattern; "salt" is a base64-encoded random salt; and "hashed password" is a base64-encoded hash. If you need to migrate hashes you can intercept people with an old password format and make them change their password the next time they log in.

As others have mentioned you want to be careful with your hashes since it's easy to do something that's not really secure, e.g., H(salt,password) is far weaker than H(password,salt), but at the same time you want to balance the effort put into this with the value of the site content. I'll often use H(H(password,salt),password).

Finally, the cost of using base64-encoded passwords is modest when compared to the benefits of being able to use various tools that expect text data. Yeah, they should be more flexible, but are you ready to tell your boss that he can't use his favorite third party tool because you want to save a few bytes per record? :-)

Edited to add one other comment: if I suggested deliberately using an algorithm that burned even a 1/10th of a second hashing each password I would be lucky to just be laughed out of my boss's office. (Not so lucky? He would jot something down to discuss at my next annual review.) Burning that time isn't a problem when you have dozens, or even hundreds, of users. If you're pushing 100k users you'll usually have multiple people logging in at the same time. You need something fast and strong, not slow and strong. The "but what about the credit card information?" is disingenuous at best since stored credit card information shouldn't be anywhere near your regular database, and would be encrypted by the application anyway, not individual users.

bgiles