Problem/Motivation
I have reported this bug to the security team yesterday and they made clear they don't consider it a security issue due to the username enumeration policy of Drupal. I believe that's a matter of some debate. I will post the issue here (as suggested), because of the reason the finding will not be forgotten when the view on this topic changes in the future.
I found that there is a noticeable difference (~ 1.5 second) between requesting a password reset for an existing account and a non-existent one. This difference makes it possible to find out whether an account exists or not (timing attack).
The noticeable difference in response timing is due to Drupal sending the mail if the account exists (which takes approximately a second) and just returning the response when an account does not exist (approximately 50 ms).
Example of response times for three consecutive requests:
| Request | Existing account | Non-existent account |
|---|---|---|
| #1 | 1,574 ms | 57 ms |
| #2 | 1,426 ms | 40 ms |
| #3 | 1,823 ms | 54 ms |
Proposed resolution
To prevent timing attacks, the following solutions could be considered:
- Change the execution order so that when a new password is requested a response is immediately returned to the user and the mail is sent afterwards.
- Another way to prevent a timing attack is to provide the password reset function a fake user so the whole process is performed on a non existing user. This will take the same amount of time and will therefore prevent a timing attack.
- Alternatively, have the application respond with the same general message for the password reset request, whether the entered mail address is valid or not. Send a mail to the entered e-mail address in both cases. In the case the user is unknown in the database simply let the message in the mail contain something like "A password reset has been requested for your account but according to our information there is no account registered with your address.".
Steps to reproduce
- Install the Drupal product with the versions listed above and configure an external mail provider.
- Request a new password for an existing user and repeat this request in a proxy tool like BurpSuite. This tool provides the response times for repeated requests.
- Perform the same request for a non-existent username and notice the difference.
Steps to reproduce
The following modules/versions have been tested:
- Drupal (9.4.8) and the SMTP Authentication Support (8.x-1.1) module was used. However, I saw the same issue arise when using Swiftmailer (so probably, the bug is located at Drupal Core).
Comments
Comment #2
avpadernoComment #3
cilefen commentedI am updating the tags according to their specific definitions. You can hover over the tags in the sidebar to see their metadata. In this case "Security improvements" is preferred over "Security".
Comment #4
cilefen commentedI am removing the a duplicate issue reference. Sorry about the noise.
Comment #5
cilefen commentedAgain, sorry about the noise. This was in the documentation component, which is maintained by a specific group of contributors. As this is not a documentation but I am moving it to the user module, the most likely spot.
It would be helpful to know if enqueuing the emails, with, for example, https://www.drupal.org/project/queue_mail, eliminates the bug.
Comment #6
solideogloria commentedI don't think sending an email to a non-existent account would be a good idea, as it would allow spam to be sent to arbitrary email addresses due to repeated requests for password reset for that email address.
Comment #8
catchWith #1189464: Add an 'instant' queue runner we could create a queue item during the form submission, and then run that queue at the end of the request (after the response is sent) to actually send the email.
Comment #10
catch#1189464: Add an 'instant' queue runner has an MR now so could be built upon here. So add a 'password reset request' queue, always create the queue item when the form is submitted, run the queue at the end of the request.
Comment #11
catch