Password validation security issue

Chris Angelico rosuav at gmail.com
Sat Mar 1 19:11:59 CET 2014


On Sun, Mar 2, 2014 at 4:49 AM, Renato <rvernucio at gmail.com> wrote:
> Hello everybody, I implemented a password validation with a Python 2.7.5 script in OpenSUSE 13.1. The user calls it passing 'login' and 'password' as arguments. I made a dictionary in the format hashtable = {'login':'password'} and I use this hash table to compare the 'login' and 'password' that were passed in order to validate them. The problem is that any user who can execute the script will be able to read it too (since it must be read by python's interpreter), and this is causing some security issues since any user can access all other users' passwords if he opens this script and reads the code.
>
> My question is: is there a way of preventing the user from reading the script's content? Is there any strategy I could use to hide the passwords from the users?
>

Yeah, that's a pretty major issue, right there :)

The most common way to deal with this is to salt and hash your
passwords. While that might sound like a great thing to do to
potatoes, it's also the best way to stop your passwords from being
sniffed.

Best practice is to combine the password with the user name and with
some fixed text (the "salt"), and then run it through a
cryptographically secure hashing algorithm. In Python 2.7, you have
the hashlib module:

>>> import hashlib
>>> login = 'rosuav'
>>> password = 'xkcd936passwordgoeshere'
>>> encrypted = hashlib.sha256(login+'NaCl protects your passwords'+password).hexdigest()
>>> encrypted
'b329f2674af4d8d873e264d23713ace4505c211410eb46779c27e02d5a50466c'

Then all you store is that encrypted password. When the user enters
the login and password, you do the same operation, and compare it with
the stored hash; if they're the same, you accept the credentials.

The reason for including two pieces of salt (a constant and the user's
login) is that it ensures that duplicate passwords don't have
identical hashes, and that your set of password hashes are unique to
you (so someone can't have a "standard set of password hashes"). So
put some other string in between the two (or somewhere else in the
string - it doesn't matter how you put the pieces together, as long as
you're consistent).

Also, as hinted in the example above, encourage everyone to use XKCD
936 compliant passwords.

http://xkcd.com/936/

This is not a joke, this is not trivial. Using this scheme, you make
passwords that are orders of magnitude stronger than the classic
"minimum 8 characters, must include uppercase, lowercase, digit,
symbol". If that gives a theoretical 80 character corpus, then it's
insisting on a theoretical 50 bits of entropy (but, as the XKCD above
shows, it's more likely to be roughly half that); you can get pretty
much the same by using four common words at an estimated 11 bits per
word, which assumes you use a pool of just two thousand words. If your
pool's larger (if you use one or two less common words), you could be
looking at a corpus of 65536 words (my /usr/share/dict/words has more
than that), which would give you 64 bits of entropy from four words.
Bank style passwords are *weak*. Long passwords are strong.

So with truly strong passwords, and a hashing system that means an
attacker has to brute-force every possible password to figure out how
to get in, you can be confident that it's safe. But don't be naive;
still do your best to protect the password hashes from scrying eyes -
on Unix, you may be able to use a setuid binary to bounce into your
script, which could then be owned by and readable only by some other
user. Or, depending on how permissions are set up, you could arrange
it so any user may run 'sudo /usr/local/bin/yourscript.py', which
would then be freely able to read from a root-owned file of passwords.
But at this point, we're outside of Python code and into Unix
security, which is quite a different topic.

ChrisA



More information about the Python-list mailing list