views:

955

answers:

11

What is the best way to handle user account management in a system, without having your employees who have access to a database, to have access to the accounts.

Examples:

  1. Storing username/password in the database. This is a bad idea because anyone that has access to a database can see the username and password. And hence use it.

  2. Storing username/password hash. This is a better method, but the account can be accessed by replacing the password hash in the database with the hash of another account that you know the auth info for. Then after access is granted reverting it back in the database.

How does windows/*nix handle this?

A: 

You could store the salt for the hashed password in another table, of course each user would have their own salt. You could then limit access to that table.

mattruma
+2  A: 
  1. A very bad idea indeed. If the database is compromised, all accounts are compromised.
  2. Good way to go. If your hash algorithm includes the username, replacing the password hash with another one will not work.

Unix stores hashes in a a text file /etc/shadow, which is accessible only to privileged users. Passwords are encrypted with a salt.

Christian Lescuyer
Someone with access to the DB though could still have access to the account. They would just need to rename the username temporarily.
Brian R. Bondy
So could you swap 2 user's passwords by moving the password hashes in that file?
Brian R. Bondy
Brian, not if the hash algorithm includes the username.
Christian Lescuyer
+5  A: 

This is a better method, but the account can be accessed by replacing the password hash in the database with the hash of another account that you know the auth info for.

There's really no way around this. Anyone who as write access to the password file has complete control of the computer.

Chris Upchurch
+3  A: 

You could use openID and save no confidential user passwords at all. Who said it is for websites only?

arturh
+3  A: 

I'd go with 2 but use some salt. Some pseudocode:

SetPassword(user, password)
    salt = RandomString()
    hash = Hashfunction(salt+password)
    StoreInDatabase(user, salt, hash)

CheckPassword(user, password)
    (salt, hash) = GetFromDatabase(user)
    if Hashfunction(salt+password) == hash
        return "Success"
    else
        return "Login Failed"

It is important to use a well known hash function (such as MD5 or SHA-1), implemented in a library. Don't roll your own or try implementing it from a book its just not worth the risk of getting it wrong.

@Brian R. Bondy: The reason you use salt is to make dictionary attaks harder, the attacker can't hash a dictionary and try against all the passwords, instead she have to take the salt + the dictionary and hash it, which makes the storage requierments expode. If you have a dictionary of the 1000 most commaon passwords and hash them you need something like 16 kB but if you add two random letters you get 62*62*16 kB ≈ 62 Mb.

Else you could use some kind of One-time passwords I have heard good things about OTPW but havent used it.

Mr Shark
Is there any benefit to using the salt as well if it is also stored in the DB?
Brian R. Bondy
Agreed, but I would suggest not using MD5 if SHA-1 is available. MD-5's vulnerabilities are well documented--SHA-1 is 'better'.
Stu Thompson
+1 for shouting about not writing your own crypto algorithms :-)
Graham Lee
A: 

The usual approach is to use option two with email:

Store user name, password hash and email address into the database.

Users can either input their password or reset it, in the latter case a random password is generated, a new hash is created for the user and the password is sent to him via email.

Edit: If the database is compromised then you can only guarantee no sensible information can be accessed, you can no longer ensure the security of your application.

Jorge Córdoba
A: 

Hash the username and the password together. That way, if two users have the same password, the hashes will still be different.

Graeme Perrow
+3  A: 

Jeff Atwood has some good posts concerning hashing, if you decide to go that route:

Jarrod Dixon
+4  A: 

This was a common issue in UNIX many years ago, and was resolved by separating the user identity components (username, UID, shell, full name, etc.) from the authentication components (password hash, password hash salt). The identity components can be globally readable (and in fact must be, if UIDs are to be mapped to usernames), but the authentication components must be kept inaccessible to users. To authenticate a user, have a trusted system which will accept a username and password, and will return a simple result of "authenticated" or "not authenticated". This system should be the only application with access to the authentication database, and should wait for a random amount of time (perhaps between 0.1 and 3 seconds) before replying to help avoid timing attacks.

stormlash
A: 

This is a bit of a non problem for a lot of applications because gaining access to the database is probably the most common goal of any attacker. So if they already have access to the database why would they still want to login to the application ? :)

Mihai Secasiu
True for a lot of applications. Not mine. Sometimes the database makes references to files on disk. Having access to the database doesn't give you access to the files on disk.
Brian R. Bondy
A: 

If the 'system' is a public website RPX can provide you with a login/user account services for the most common providers, like OpenId, Facebook, Google, etc.

Now, given the way you formulate your question I guess the 'system' you're talking about is more likely an internal windows/linux based enterprise app. Nevertheless; for those googling around for login/user account providers (like I did before a came across RPX), this could be a good fit :)

Kjetil Klaussen