Problem/Motivation
This is a D7 backport of: #2828724: Username enumeration via one time login route . We probably want to backport this security improvement.
For D7, this is the relevant part:
For Drupal 7 or Drupal 8, if you're logged in and visit a URL like the above it happens via this message:
Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user.
Steps to reproduce
Proposed resolution
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #8 | 3326994-8.patch | 2.25 KB | poker10 |
| #8 | 3326994-8_test-only.patch | 841 bytes | poker10 |
Issue fork drupal-3326994
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #4
klonosNot sure if we want to keep translatable string parity with D9, but for the respective issue in Backdrop CMS we ended up using this generic message that doesn't mention any username at all:
I have created a MR here: https://git.drupalcode.org/project/drupal/-/merge_requests/3581 (sorry, I accidentally left the target branch as 10.1.x initially, then changed it to 7.x)
Comment #5
poker10 commentedThanks for the MR!
I would prefer to avoid changing frontend strings in this D7 phase if possible. Probably it will be better to reuse an existing string "The one-time login link you clicked is invalid.". See the proposed resolution in the D10 issue here: #3327294: Username enumeration via one time login route when logged in as another user. We could probably introduce a check if the link is valid and only then output the existing message, otherwise we can output: "The one-time login link you clicked is invalid.".
Comment #6
poker10 commentedComment #7
poker10 commentedD10 issue was committed. We can check the approach to see if the similar can be used in D7.
Comment #8
poker10 commentedUploading a patch which backports possible parts from the D10 patch (different approach as in the current MR). I have not created a separate validation function (as in D10, see
validatePathParameters()), because the D7 code is a bit different with more conditions (it is checking hashes from URL or session -$session_reset_hashand$hashed_pass), so it would not be easy to refactor it to one simple function as in D10. This patch uses the same approach to verify a valid hash as it uses a few lines below (see https://git.drupalcode.org/project/drupal/-/blob/7.x/modules/user/user.p...), which is not super ideal, but on the other hand, it is not an invasive change and it fixes the problem with enumeration. So I think this approach is worth a try.Tested the patch also manually:
1. If a logged in user uses an invalid reset link (like /user/reset/1/1/1), then:
Another user (XXX) is already logged into the site on this computer, but you tried to use a one-time link for user ZZZ. Please logout and try using the link again.The one-time login link you clicked is invalid.2. If a logged in user uses a valid reset link (like /user/reset/1/1673978256/rCRqJ0X800xD0eKVFhBmMnkdpDgKtKkzYIGav7sBqSg), then the message would be the same (unchanged) before and after patch:
Another user (XXX) is already logged into the site on this computer, but you tried to use a one-time link for user ZZZ. Please logout and try using the link again.The benefit of this approach is that we do not need to change any frontend-facing strings.
Comment #10
bramdriesenI took the time to look into what was done in the D10 patch, actually @poker10 described it pretty well 😇.
Maybe one remark, why was the error message changed from "You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below." to "The one-time login link you clicked is invalid.".
I like the formulation of the D10 version a bit better as the one here in the patch. For the rest I think this can be set to RTBC.
Comment #11
poker10 commented@BramDriesen thanks for the review!
I do not think that the message is different in D7 vs D10. If we look at
UserController::resetPass()(link) there is a condition which checks if user is authenticated. If yes and the password reset link is for another user, there are only two options:If the link is valid:
If the link is invalid:
The same situation is in D7 code in
user_pass_reset()(when user is logged in), see: https://git.drupalcode.org/project/drupal/-/blob/7.x/modules/user/user.p...I tried to make the smallest impact as possible, so the patch only changes the behavior when the link is invalid - this previously displayed the message with username:
But after the patch applied, the message from else is displayed in such case:
The message you mention (
You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.) is displayed only when user is logged out (so the password reset form is accessible), which is not the case we are fixing here (D7 does not seems to output username if user is logged out, only if is logged in).Comment #12
bramdriesenAha okay! That explains 😉
In that case, pretty sure we can set this to RTBC!
Comment #13
poker10 commentedAdding a tag for the final review from another D7 maintainer before commit.
Comment #15
mcdruid commentedThis looks like a good backport, although the implementation's quite different, for the reasons that have been well explained.
Thanks!