Until today, I could never muster the courage to look into the source code of anything. Part of it was Imposter Syndrome, and part of it was . . . well, I guess, Imposter Syndrome again! “The source will never make sense to you”, the little voice inside my head would tell me and I’d go back to writing simple command line programs. Today, however, I took the red pill.
While learning the authentication system in Django, today I got interested in the
authenticate() method. How is it able to authenticate a user, I asked myself, given only username and password? So I decided to look into the source (the GitHub repository I cloned was a whopping 137 MB!)
I found the relevant file, and right there, is sitting a very friendly and innocent function. However, I noticed something very interesting:
try: user = UserModel._default_manager.get_by_natural_key(username) except UserModel.DoesNotExist: # Run the default password hasher once to reduce the timing # difference between an existing and a non-existing user (#20760). UserModel().set_password(password)
Ah, what is that comment? Very interesting. Normally I wouldn’t know where to look next, the but the clue is right there: Issue #20760. A Google search revealed that this code is a workaround for the following possible security vulnerability:
When attempting to authenticate using django.contrib.auth, if a user does not exist the
authenticate()function returns None nearly instantaneously, while when a user exists it takes much longer as the attempted password gets hashed and compared with the stored password. This allows for an attacker to infer whether or not a given account exists based upon the response time of an authentication attempt.
This can be seen much more clearly when the number of rounds on the password hasher is set to something high like 100000.
authenticate(), create a dummy user and set its password. If no user is returned from the database query, check a password which is guaranteed not to match against the dummy.
This explains why many login systems (even your Linux box) takes considerable time to report wrong password errors. As a programming gradually increasing in strength, I’m overjoyed! Little gems like these brightne my day, and today the sun has suddenly started shining extremely brightly!