Passwords in Django

Here Ive created an account with the password testing and stored it as an unsalted MD5 hash: >>> from django.contrib.auth.hashers import make_password >>> user.password = make_password(password='testing', salt=None, hasher='unsalted_md5') >>> user.save() >>> user.password 'ae2b1fca515949e5d54fb22b8ed95575' As soon as I authenticate the account the password is re-hashed with PBKDF2: >>> from django.contrib.auth import authenticate >>> authenticate(username='tester', password='testing') >>> user = User.objects.get(username='tester') >>> user.password u'pbkdf2_sha256$15000$lPSA3r6AwELv$/6Frb75xtX5xmA8Ezcnl0UxPmHpUaeleY+QqM/dMRLw=' As of version 1.7.3, Django supports nine hashing types and variations which is handy for importing user accounts and their password hashes from other systems..>>> from django.contrib.auth import hashers >>> from pprint import pprint >>> pprint(hashers.HASHERS.keys()) [u'bcrypt_sha256', u'sha1', u'pbkdf2_sha256', u'pbkdf2_sha1', u'crypt', u'unsalted_md5', u'unsalted_sha1', u'bcrypt', u'md5'] Downgrades as well as Upgrades The only downside to password hash upgrading is that if you do use PBKDF2 but use a higher iteration count than what is hard-coded into the PBKDF2PasswordHasher class in django.contrib.auth.hashers then the iteration count will be downgraded to that given hard-coded value..Django 1.7.3 set this iteration count to 15,000, Django 1.8 sets it to 20,000 and the current master branch of Django which targets the version 1.9 release of Django set the iteration count to 24,000..Here is a demonstration of a downgrade using Django 1.7.3..Ive hashed a password 50,000 times and its downgraded to 15,000 after authentication: >>> from django.contrib.auth import authenticate >>> from django.contrib.auth.hashers import PBKDF2PasswordHasher >>> hasher = PBKDF2PasswordHasher() >>> user.password = hasher.encode(password='password', salt='salt', iterations=50000) >>> user.save() >>> user = authenticate(username='tester', password='password') >>> user.password u'pbkdf2_sha256$15000$NdqimFkxkuIe$YXO6x1A4XlVaFyu6V+Y/pXHnwpmNAcyFeX88R4JXf1k=' Why is computationally expensive hashing so important?.If the raw password hash values, salts and iteration counts themselves were to ever be exposed it extremely computationally expensive to try and guess what the original password that was used to create the hash….or it would be if the passwords were hashed with PBKDF2, HMAC, SHA256 and tens of thousands of iterations..If you use a weak hashing algorithm, such as unsalted MD5, then it becomes trivial to find out what the original passwords are..To demonstrate, Ill create an unsalted MD5 hash for the string elephant123: >>> from django.contrib.auth.hashers import make_password >>> make_password(password='elephant123', salt=None, hasher='unsalted_md5') 'e68a95aadb0c73dfd968513174de4ddf' If I paste e68a95aadb0c73dfd968513174de4ddf into the form on md5crack it tells me in less than a second that elephant123 is a possible string that the hash e68a95aadb0c73dfd968513174de4ddf represents..MD5 has demonstrated attacks, SHA-1 hashes could be broken with a large amount of computing power but SHA256 (which Django auths PBKDF2 class is configured to work with) has no known complete attacks..And just in case, having a configurable iteration count means password hashes can be upgraded as computers become more powerful..Why are some passwords too long for Django?. More details

Leave a Reply