Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Passwords, hashes, and salt

by Mr_Person (Hermit)
on Jun 24, 2005 at 17:57 UTC ( [id://469778]=perlquestion: print w/replies, xml ) Need Help??

Mr_Person has asked for the wisdom of the Perl Monks concerning the following question:

I'm writing a web app where users' passwords will be stored in a database. I know that I should use a hash function with a salt for storing the passwords, but most of the suggestions I've seen involved making your own system. Are there any modules out there that do it for you? I found Crypt::PasswdMD5, but it seems to go throught a lot of extra trouble just to be compatible with an existing implimentation, plus I know that MD5 is sorta on the way out.

If I do need to write my own, any suggestions for how to go about it?

Thanks!

Replies are listed 'Best First'.
Re: Passwords, hashes, and salt
by waswas-fng (Curate) on Jun 24, 2005 at 18:37 UTC
    There is really no need to use someone else's implementation unless you need to share the auth with another application. If you have full control of the app, a good way to do it is to use sha1 digests with a salt. such as:
    use strict; use Digest::SHA1; my $plaintext="Test1ng"; #generate a two char salt... my $salts= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345 +6789./"; my $s1 = rand(64); my $s2 = rand(64); my $salt = substr($salts,$s1,1) . substr($salts,$s2,1); my $sha1 = Digest::SHA1->new; $sha1->add($salt.$plaintext); # the enc pass is presented with the plaintext salt as the first two c +hars. my $encpass = $salt. $sha1->hexdigest; print "$encpass\n"; This outputs: kcc68a68507e8636a1a9a6badc059342b19a12c58e And to test the password: use strict; use Digest::SHA1; my $storedpass='kcc68a68507e8636a1a9a6badc059342b19a12c58e'; my $plaintext="Test1ng"; #pull salt from the saved password so you can compair... my $salt = substr($storedpass,0,2) ; my $sha1 = Digest::SHA1->new; $sha1->add($salt.$plaintext); # the enc pass is presented with the plain-text salt as the first two +chars. my $encpass = $salt. $sha1->hexdigest; print "if $encpass = $storedpass the password is correct...\n"; which outputs: perl testpass.pl if kcc68a68507e8636a1a9a6badc059342b19a12c58e = kcc68a68507e8636a1a9a6 +badc059342b19a12c58e the password is correct...
    The reason you "salt" the plain-text is so that if you have 30,000 users in the password database and you want to check to see if any use the password "greatwork" you have to digest it against up to 30,000 salts instead of just just digesting it once and moving on to the next word in the attack. Adding more than 2 random chars to a salt potentially adds more difficulty as you have more users in the database, as there would be less salt overlap. I hope this makes sense...


    -Waswas
      Okay, that looks pretty good. The main reason I wanted a premade module is that I've seen a lot of examples where people tried to impliment their own encryption/security schemes instead of going with something that's been proven and got burned by it. When it comes to something like cryptography that I don't fully understand, I'd prefer to use code written by someone that has a better understanding than myself.
Re: Passwords, hashes, and salt
by Zaxo (Archbishop) on Jun 24, 2005 at 18:33 UTC

    Crypt::PasswdMD5 is, in practice, easy to use. The salt is prefixed to the the returned password hash, so you don't need to use a constant one. Just extract that substring from the stored hash and use it as salt for the offered password, then compare strings. When you first store a password hash, any random salt will do. The randommer, the better.

    The purpose of salt is to make wordlist dictionarys impractically large.

    After Compline,
    Zaxo

Re: Passwords, hashes, and salt
by dynamo (Chaplain) on Jun 24, 2005 at 18:22 UTC
    You are going to need a hash function to store your passwords, and MD5 is (IMHO) decently secure. Moreso than plain old crypt with salt at least. I'm not sure how salt really adds anything useful to the picture - either you have a fixed salt value, in which case it can be ignored as part of the crypt algorithm, or you have a dynamically generated salt value, usually based on some input from the user record or the password itself - which can also pretty much be ignored as part of the crypt algorithm.

    It's fairly straightforward how to implement this yourself - check the hashed password against the database for an auth request, hash and store the password when creating a user or changing a password. What else did you need to know?

      Adding salt does two things:

      1) It makes it harder to brute force the password list.

      2) If person A knows his password hashes to the same value as person B's -- some websites stupidly publish users that had the same password hash -- person A could login as person B using their own password without even knowing person B's password. Adding salt would create different hashes (even for the same password), eliminating this problem.

      usually based on some input from the user record or the password itself

      Salts are usually random. Ideally, each user has a different salt. They must definitely NOT be based on the password since the salt must be known. Basing it on the password would leak info about the password.

      Crypt::PasswdMD5 creates a salt for you if you don't specify one, according to the documentation.

      I'm not sure how salt really adds anything useful to the picture
      Salt makes your passwords less vulnerable to dictionary attacks.
Re: Passwords, hashes, and salt
by Anonymous Monk on Jun 24, 2005 at 18:24 UTC
    You'll maybe have to explain a little bit better why you think...
    use Crypt::PasswdMD5; $cryptedpassword = unix_md5_crypt($password, $salt);
    ...is a lot of extra trouble, especially since rolling your own would seem to be a lot of busy work for very little gain.
      Because there have been multiple documented attacks against MD5. You don't need the password if you can run out and come up with a new plaintext that ends up with the same digest.


      -Waswas
      Oh, I didn't mean that using the module would be too much trouble. In fact, it looked like the easiest thing to do. I was refering to how the module worked internally, it looks like there's some extra stuff that it does just so it can be compatible with Unix and Apache MD5-based crypt. That, and like I mentioned, it is just MD5.
Re: Passwords, hashes, and salt
by TedPride (Priest) on Jun 24, 2005 at 19:26 UTC
    The main problem here is preventing two users with the same password from being able to log in as one another, right? Just merge the user name and password and salt in such a way that the hash is unique for every user name and password pair, and completely unguessable through dictionary attack or brute force. For instance, you could add the ASCII values of the characters in the user name and in the pass (wrapping, of course), then insert the characters of the result into every 4th character of a 50-character salt. This is easily reproduced if you know the method used and the salt, but totally impossible to guess or brute force.

    Personally though, I'd work more on making sure the database is secure from prying eyes, rather than hashing stored passwords. Storing passwords as irreversable hashes means there's no way to retrieve the password if the password is forgotten, meaning in turn that you need a secondary verification system - which is always less secure and usually fairly easy to social engineer. If you ARE going to make passwords irreversable, make them short (no more than 3-4 alphanumeric characters), with lock-out of IP / user on failure to log in 3 times in a row. A short password is much easier to remember, and pretty much eliminates the need for a secondary verification system.

    The weakest link is almost never site security, but rather human laziness and inability to remember things.

      I think you miss the purpose of a salt trap door encrypted password. The goal for a salted password is to be any reproducible process which does not expose any information about the password and that changes the final digest value so that A: users with duplicate passwords are not apparent, and B to brute force a given plaintext against a database of passwords is takes N (computationally expensive) digest attempts where N is the number of usernames. The salt should be easily guessable, in fact most of the time it is plaintext. What you suggest in your opening paragraph is to create your own digest or encoder -- this is not good idea. LOTS of time and research goes into trap door encryption and digests to make sure that the they are secure -- there is good reason for this. MD5 for example had a ton of eyes looking at it over the years and is only recently broke. I do not know you personally Ted, but I would not bet money on the fact that you could produce a new un-bruteforcable (or even worse yet, un-flat-out-breakable) trap door encryption scheme. At best it would be OBFU. They are very hard to do well.

      One (of many) reason almost all secure apps use trap door encryption for passwords is that it is not reversible. That is KEY. One such attack that this defeats is your system administrator, which has access to all of your accounts and passwords, knowing the passwords when he gets laid off next week. To reset or change your password other sources of information are used for verification such as your email address with a click back, or all the way up to physical request in person with multiple forms of ID. Having plain text stores of passwords totally blows the user:pass concept of proving identity. Just think of this: if your server is compromised, and you can determine the break in exploit and time table, with plain text passwords in your database you cant roll back to the pre-exploit time and patch the issue. you have to have everyone on the system reset their password.


      -Waswas
Re: Passwords, hashes, and salt
by dynamo (Chaplain) on Jun 24, 2005 at 18:34 UTC
    If you were suggesting writing your own hash function to use instead of MD5, don't even consider it if security matters to you. MD5 has been through years of testing and review, and although there have been chinks in the armor, it's still quite usable. SHA-1 is a good alternative though, if you can find mature code for it.
      There is more than a few chinks -- MD5 is broke, its getting worse day by day.

      look here (offsite:rub.de) for an article that explains the current publicly announced state of things. I as this gets more eyes on it, it will get even worse. MD5 digests should be considered almost as insecure as mad XOR magic. =)

      Update: just wanted to add that SHA-1 has some of the same weaknesses as MD5, but as of yet they have not been able to break it like MD5. If you are really worried you can goto something like Digest::SHA256 for a digest, but it may not be worth it yet.


      -Waswas
      No, not at all. I may not know too much about the math behind hashing functions, but I know enough to know that I shouldn't even try to make my own for real world use! :-)
Re: Passwords, hashes, and salt
by TedPride (Priest) on Jun 25, 2005 at 06:57 UTC
    You're using a two-character salt, different for every user, which is viewable as part of the hash. I'm suggesting pretty much the same thing, except the user name is the unique part of the salt and the process is more obfuscated. What am I missing here? Did you think I wasn't going to MD5 or SHA-1 the result? Heh.

    Incidently, I fail to see how any security method is going to save you if the person with root gets pissed off. He can social engineer people; he can redirect himself a copy of their user names and passwords on login; he can scan data streams and memory; etc. All he needs is a few logins to make your entire database unsafe, unless you know exactly which ones he has. Face it, you're screwed. The only thing you can prevent is him knowing everyone's password in one easy step, but why would that matter when he has root? He controls everything.

    EDIT: I suppose if you know who logged in when and also when it was he inserted the redirect, you could identify which users he had the login info for and reset just their passwords. To prevent this, he'd also have to edit the logs before every site backup, which I admit would add a level of complexity to things. Still, anyone with half a brain would most likely have no trouble doing this.

      All I can say is that there is very good reason that unix password files have been trap door encrypted for decades. One of the foundational principles in security is that given enough time and want any system can be broken. This does not mean that you give up on the details. You have a few doors with locks on them at your house, what is the point when you have very breakable windows right next to them? Thats what I read in your response.

      You Said: Just merge the user name and password and salt in such a way that the hash is unique for every user name and password pair, and completely unguessable through dictionary attack or brute force

      Which is one of the things in your post that made me realize you did not have your eye on the prize. Salt guess-ability is not a factor, they do their job while being totally known and visible. in fact you could just inc 01 .. N for salt on each new username and be done --all that matters really is that they are different per password. All your suggestion does in this post is to try to obfu salt into the password/hash -- this buys you nothing.

      Later on you say: Personally though, I'd work more on making sure the database is secure from prying eyes, rather than hashing stored passwords. Storing passwords as irreversible hashes means there's no way to retrieve the password if the password is forgotten, meaning in turn that you need a secondary verification system - which is always less secure and usually fairly easy to social engineer. If you ARE going to make passwords irreversible, make them short (no more than 3-4 alphanumeric characters), with lock-out of IP / user on failure to log in 3 times in a row. A short password is much easier to remember, and pretty much eliminates the need for a secondary verification system.

      which I see so many issues with I cant really spend the time going into it in detail. All I will say is that the second level password reset systems are as secure as they are designed to be -- while your posting account on perlmonks may be easy to get reset, your cert and pass at a DOD installation may require physical request with ID. It is all in the design and risk assessment of the particular site -- You have to remember at the end of the day user:pass systems are there to verify identity. If anyone on your system can freely grab user:pass info -- they can't be used to verify identity.



      -Waswas

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://469778]
Approved by injunjoel
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (2)
As of 2024-04-19 20:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found