- Date: 2020-04-21
- Project: wagtail
- Vulnerability: Timing attack (side-channel attack)
- Severity: based on similar vulnerabilities this would be a Moderate severity, 3.7 CVSS score
Vulnerable code: wagtail/core/forms.py#L16, in all versions from v0.8.8 onwards.
class PasswordViewRestrictionForm(forms.Form):
[...]
def clean_password(self):
data = self.cleaned_data['password']
if data != self.restriction.password:
raise forms.ValidationError(_("The password you have entered is not correct. Please try again."))
Timing attacks rely on observing the time it takes for a given auth check to complete. If the time varies depending on how "close" the auth check is to succeeding, then an attacker can measure this time difference to determine what the auth details are.
This implementation is vulnerable to a timing attack because string comparison is done character-by-character in Python, so the program will take longer to execute the closer the submitted password is to the configured one.
From my understanding timing attacks are meant to be somewhere between hard and impossible under real-world circumstances "over the internet", where the timing difference signal gets lost in the noise of too many other factors. However this might not be a problem for more sophisticated attacks using statistical models / started from the same data centre. As far as I understand timing attacks are confirmed to be possible over a local network.
The fix is to make sure the auth check takes a constant time regardless of what input is provided,
- Use a constant-time string comparison function such as
hmac.compare_digest
- Or use a Django wrapper around that function such as django.utils.crypto.constant_time_compare
- Rails basic auth username and password
- express-basic-auth username and password
- Django enumeration of users