Problem/Motivation
RegisterForm exposes the plaintext password both in the form state and on a dynamic password property on the user entity object.
Exposing plaintext passwords is a bad security practice, it could lead to contrib code handling it incorrectly, leaking it if the object is serialized, etc. We should not expose it on the entity and we should remove it from the form state as soon as we don't need it anymore (after the form submit handler has been called).
In \Drupal\user\RegisterForm line 115 has:
// Add plain text password into user account to generate mail tokens.
$account->password = $pass;
Drupal 8 doesn't support such a token, and it looks like this in NOT the hashed value set by \Drupal\Core\Field\Plugin\Field\FieldType\PasswordItem because we copy it before calling $account->save();
The same lines exist in Drupal 7 and is also a possible (minor) security weakness since the plain text password may be passed through the mail system even though Drupal 7 no longer supports a plain-text password token (Drupal 6 still does).
In Drupal 7 see line line 3925 in user.module:
// Add plain text password into user account to generate mail tokens.
$account->password = $pass;
Proposed resolution
Deprecate accessing this property.
An in a future release remove the code that sets $account->password.
Remaining tasks
User interface changes
none
API changes
none
Data model changes
none
| Comment | File | Size | Author |
|---|
Issue fork drupal-2648272
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:
- 2648272-deprecate
changes, plain diff MR !14470
- 2648272-remove-outdated-code
changes, plain diff MR !12163
- main
compare
Comments
Comment #2
pwolanin commentedQuick 1st pass patch
Comment #3
mgiffordRemoving code seems fine since it seems not to be supported in D8 any more. I can see how unsetting the pass value could help, but that should be described in the issue more.
Manual testing for the generated mail tokens is probably a good idea too.
Comment #6
dpiDrupal 6 had the
!passwordtoken for passwords. There is no official[user:password]token for Drupal 7 or 8. Unfortunately I cant find an issue outlining rationale for removing the password token in D7.Perhaps this issue should be about adding a password token, and changing the
$account->passwordcode to be something that isnt creating dynamic properties.If it is decided that we dont need a password token, then remove the above code.
For reference, the Registration Password Token project is dedicated to adding this token to Drupal 7 and 8. Both versions rely on this dynamic
$user->passwordvalue to be set.Comment #7
dpiActually this token would need to be made available on user save events to accommodate potential password modifications on the edit form. So this doesnt just affect user registrations
Comment #10
kingandy@dpi, I believe the primary reason for removing the password token is that it is bad security practice to display or transmit a user's password in any form. We can argue about what methods of data transfer are and are not safe, but at the end of the day the only 100% guaranteed secure decision is to simply not expose it, and that's the decision the Drupal team have made.
On a technical level (AIUI) it is no longer possible to extract a user's password for display, as the login system has been moved over to a one-way encryption algorithm - the system itself can't decrypt a stored password. (There's really no need to, even at login - instead it encrypts the entered password using the same algorithm and compares it with the stored one.) So that is a pretty big barrier to making such a token generally available even if you wanted to, which, as noted, is a super bad idea.
The RPT module does a very specific job of making the token available in registration emails, which it's only able to do because the password has not yet been encrypted at that point (the form submission is still available). Adding a password token to the system does not look like an practical or desirable option at this time.
Comment #11
kingandyRestoring the former task title and category/status.
Comment #19
smustgrave commentedIf this is a bug it will need a test.
Comment #22
mr.baileysWe should be careful when removing this, since some contrib modules seem to rely on this property being set (so a bit of an undocumented API?). See for example https://www.drupal.org/project/logintoboggan/issues/1165126.
Comment #23
dcam commentedIt doesn't make sense to me that this issue was filed as a bug report. A quick search for other "dead code" issues in the Core queue shows that they're mostly/all Tasks.
I considered the suggested test:
I even wrote one out, but in the end this is no different from a Functional test where the login form is submitted. That's covered by
UserRegistrationTest. If I'm wrong, then tell me. Needing a test for this doesn't make sense to me. The other dead code issues I checked don't require a test for it either. So I'm removing the Needs Tests tag (along with other superfluous tags).Aside from that, I also wondered why PHPStan didn't pick up on this. This line contains an undeclared class property assignment. I figured that should be setting off a standards error. But it doesn't because Core only lints with PHPStan level 1. Those warnings are activated at level 2. You can cause an error to occur manually with the command
vendor/bin/phpstan analyze --configuration=./core/phpstan.neon.dist -l 2 core/modules/user/src/RegisterForm.php.Comment #24
smustgrave commentedStill seems to be solving a problem vs just removing code so probably would still vote for a test to show whats needed
#22 should be considered too
Comment #25
dcam commentedWould you prefer to deprecate it instead of removing it immediately?
Comment #28
prudloff commentedI added a test.
Comment #29
smustgrave commentedthink this should have an issue summary about why it's needed, not super clear. Also how are we covering instances in contrib that could be relying on this? See #22
Comment #30
prudloff commentedI added an explanation at the beginning of the summary.
This is an undocumented property. Is it OK to remove it in a major release or do we need to deprecate it first?
Comment #31
smustgrave commentedWould assume it would need some kind of deprecation.
Comment #32
smustgrave commentedWonder if something similar can be done like in
EntityBasefor originalComment #37
prudloff commentedI opened a new MR that deprecates the property instead of removing it.
Comment #38
smustgrave commentedUpdated title to match what's going on. Am wondering if this one should be removed in 13 but will let committers decide. Seems like a good deprecation.
Comment #39
longwaveThanks for the discussion above. While contrib modules do seem to be using this, given this is a security improvement I think we should just get rid of it sooner rather than later - so let's deprecate in 11.4 for removal in 12. It is obvious we should not be storing plaintext passwords at all and modules that were relying on this feature will have to find another technique if they really need it.
Crediting everyone on this issue for the discussion. Tagging for a followup to remove the deprecation and the setter from main/12.0.
Committed and pushed 9e6f0a2cd9f to main and ba93099d48a to 11.x. Thanks!
Comment #44
longwaveOpened #3571296: Remove plaintext $account->password as followup.