views:

935

answers:

5

What is the proper way to work with Passwords you don't want to store in clear text in a database? What are my options in NHibernate / Castle ActiveRecord?

UPDATE: I was interested in how others handle this with NHibernate / Castle ActiveRecord. And if there was anything built into NHibernate or Castle ActiveRecord.

+1  A: 

You should either encrypt or hash a password. Hashing is a bit more secure (depending on the algorithim of course). Because it can't be reversed; however, encryption can be more functional since you can have a retrieve password option. With hashing you have to generate a new password..

As for nHibernate / castle you should handle the algorithim inside your business objects IMHO seperated from the persistance mechanism.

JoshBerke
+2  A: 

The best way is to use a UserType. Here's one that implements transparent password encryption.

I'll copy common questions like this to the ActiveRecord wiki.

Mauricio Scheffer
+2  A: 

Hash the password. Don't encrypt - it's complex and/or unsafe. There's no conceivable circumstance in which it wouldn't be OK to reset the password based on some other verifiable criterion in an ordinary line-of-business app or Web site. I'm not sure from the question whether or not you're familiar with the principle of hashing a password, so I'll explain from the basics...

When the user selects their password initially, you run a one-way hash algorithm on the text. This produces a signature - an output that will always be produced if you input the same string into the hash algorithm. The key is that you can't get back to the password from the hash (hence one-way). You then store the hash, not the password. When the user comes back they have to type in their password again, you hash this using the same algorithm and compare the resulting value to what's in the DB - if they match, you know the user enterered the same string again, but you still don't know, or need to know, what it is. This is much more secure than solutions based on encyrption where you can always recover the plaintext if you know the key, which by definition has to be known to the server in order to validate the password input.

A simple way of hashing a string in .NET is to use System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(), which despite its lengthy name is a simple function provided for those using ASP.NET Forms Authentication, but just as useful elsewhere. You can specify MD5 or SHA1 as your hash algorithm (or indeed other hash algorithms if supported by future framework versions). I recommend SHA1 because MD5 is known to have weaknesses, but then SHA1 probably does too.

However - there's a flaw in this scheme. If multiple users choose the same password, they will have the same hash. If a hacker gets access to your data, they can run a brute-force attack hashing common strings and comparing these against your stored data. If they get a hit, they've cracked all the accounts using that password. Since users tend to pick crappy passwords and hate being made to pick secure ones they can't remember, this makes a system based on simple password hashes a little brittle.

What you should do is salt the hash. This just means prepending or suffixing the original data - the password - with a random string of characters. This salt needs to be as random as it can be and at least a few chars in length (I recommend 5 as a minimum) and preferably of random length. You store the salt (unobfuscated) in a column in the DB alongside the hashed salt + password combination. When the user returns you prepend or suffix the salt to their input in the same way, and then do the hash comparison as before.

This reduces the effectiveness of a brute force attack because every user should have a different hash even if they have the same password. You can safely store the salt in the DB because working out a string from its hash is just as hard when you know some of the string as it is when you know none of it, provided the password itself is longer than the salt and long enough and strong enough to take a long time to crack by brute force (at least 6 chars with at least one case change and a number or non-alphanumeric, I'd say).

If someone has unlimited access to your data for unlimited time, they'll eventually crack the hashed passwords. But eventually could be months or years. And provided you know you've been compromised, you can get everyone's password changed well before it becomes a problem.

DotNetGuy
+1 Thanks great info. I'm going to update my question though. I was thinking more about how Encryption/Hashing should work with NHibernate and CAR. But others should vote this up based on the explanation of hashing and security.
tyndall
Yeah, point taken - and Mausch's answer above tells you about how NHibernate handles transparent encryption via UserTypes. Because hashing is one-way I don't know of any specific support for it in NHibernate and hence in AR. I'd always do this myself within the domain objects even as a big NH user.
DotNetGuy
+1  A: 

I would suggest not using UserType for the one-way hashing, not unless you have a plan that will preventing continually rehashing a hashed password on subsequent calls to NullSafeSet().

Instead, I would recommend that you use a backing field on your Password property, apply the hash method in the setter and setup your mapping to use the field access.

Kurt Johnson
A: 

sorry maybe it is irrelevant anymore for your, but i hope can help someone else.

Using uNhAddins is the easiest way I found, you only need to care about the HBM that's all.

check this hbm example

Hope that help

ktutnik