Account enumeration through timing attack in password verification in django.contrib.auth
|Reported by:||Owned by:||Aymeric Augustin|
|Severity:||Normal||Keywords:||security authentication timing enumeration|
|Cc:||jpaglier@…, eromijn@…||Triage Stage:||Ready for checkin|
|Has patch:||yes||Needs documentation:||no|
|Needs tests:||no||Patch needs improvement:||no|
This bug is an example of http://cwe.mitre.org/data/definitions/208.html and very similar to https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2004-1602 .
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.
In 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 mitigation strategy does not entirely mitigate a timing attack of this fashion. It does, however, greatly increase the amount of work required to gain usable information from it. For example, with a smaller variation between the two cases (user exists, user does not exist), the differences in lengths of time become much harder to distinguish from network transit times.
Change History (31)
comment:1 Changed 3 years ago by
|Owner:||changed from nobody to anonymous|
|Status:||new → assigned|
comment:5 Changed 3 years ago by
|Triage Stage:||Unreviewed → Accepted|
comment:17 Changed 3 years ago by
|Owner:||changed from anonymous to Aymeric Augustin|
|Patch needs improvement:||unset|
|Triage Stage:||Accepted → Ready for checkin|