Problem/Motivation
When increasing the minimum required password strength, this new minimum required password strength level will only be enforced for users who change their password.
Problem #1: Users who don't try to change their password will be able to keep using their old (weak) password to log into the site.
Problem #2: Logged in user with a weak password will remain logged in, and depending on the site configuration, users may never log out, leaving their weak password in place for attackers to break into their account.
Proposed resolution
Track individual user's password strength score when they set their password, and when their password score is lower than the site-wide minimum score, force them to change their password by redirecting them to their account edit form. User's individual score is kept in the users table data field (all operations are done on a per user basis, no bulk emailing or anything). The last policy change timestamp is stored as in Drupal variable.
Authenticated users workflow: to prevent users who may be in the middle of a form submission from losing their work, implement a 2h time-window of leeway during which a warning dsm will tell them know they have to change their password with a link if they want to do it right away. Once 2h after the policy change have past, they will get redirected to the user edit form where they can change their password.
Logged out users workflow: for users who were logged out at the time of the policy change, they will be forced to change their password right after they log in, and will not be able to go anywhere else on the site until they have changed their password.
Remaining tasks
Agree on approach and write a patch.
User interface changes
TBD
API changes
TBD
Comment | File | Size | Author |
---|---|---|---|
#19 | 2420047_19.patch | 12.13 KB | greggles |
#18 | interdiff.txt | 859 bytes | banviktor |
#18 | 2420047_18.patch | 12.74 KB | banviktor |
#16 | 2420047_16.patch | 12.77 KB | banviktor |
#14 | 2420047_14_ps_force.patch | 11.73 KB | scor |
Comments
Comment #1
gregglesI like everything about this except:
Isn't that column going away? I suggest a new database table: uid | password_strength_score.
Comment #2
coltraneThanks for proposing this scor! I'm in favor of it all but for the proposed authenticated users workflow. I do agree with greggles that a new separate table is best to store a user's score and set time.
I agree with problem #2 but I'm not sure the risk of it is worth the complexity costs of implementing the proposed messaging and 2 hour window solution. I anticipate that logic being somewhat complex to write as well as a further support burden for integration with other modules and workflows. How about instead we:
* have a README and documentation section on mitigating this risk, including links to relevant modules
* relevant modules could include options such as forcing all authenticated users to be logged out on new strength, and
* possible separate module that implements the messaging and window feature
Comment #3
scor CreditAttribution: scor commented@greggles: Absolutely right! Here is what user_schema() says: Use of this field is discouraged and it will likely disappear in a future version of Drupal.
@coltrane: I'm going to reduce the scope of this issue to only support the "logged out" workflow. I will create separate follow up issues for potential improvements. The only way to deal with logged in users for now will be to force them to change their password by for example forcing a log out via some other means.
Comment #4
scor CreditAttribution: scor commentedHere is my implementation for D7.
Comment #6
gregglesI think there needs to be a hook_update to install this, right? And also to calculate scores for existing users? I'd be fine if the latter item were provided by a drush command instead of a hook_update, since it will potentially be expensive.
comment typo "user_save()" ?
Comment #7
scor CreditAttribution: scor commentedGood point, I will add that. Good catch on user_saved() too!
Nope, we can't do that because we need the raw password to calculate the strength. All users will be assumed to have password too weak and will be asked to reset. From then onwards, we will keep track of their strength. We could potentially add an checkbox in the admin interface to toggle this password change on login. It could be enabled on new install, but an update function could disable it until the admin has warned users they will need to reset their password?
Comment #8
gregglesRight...that makes sense about not doing it for existing passwords.
Comment #9
scor CreditAttribution: scor commentedTake #2: Actually, there is a solution for that! #2424253: Capture password strength during the login process. That means we could enable this password reset policy via an update function from the get-go once we have #2424253 committed...
Comment #10
scor CreditAttribution: scor commentedIt occurs to me that with #2424253: Capture password strength during the login process we would not really need to keep track of each user's password strength in the DB to solve the "force password change at login" use case. That said having the strength in the DB could open up other applications (for example if we wanted to react to a strength requirement increase immediately).
Comment #12
scor CreditAttribution: scor commentedFolding the idea of #2424253: Capture password strength during the login process here since the code change is actually quite small. I've also fixed @greggles's issues of #6. Once you install this patch / upgrade your module, you will now be able to log in with your strong password without being asked to change it if its strength is as good as the minimum strength, and the strength will be tracked in the DB going forward.
Comment #13
gregglesThanks for the improvements, scor. I did a quick visual review and it looks pretty thorough :)
Comment #14
scor CreditAttribution: scor commentedThanks @greggles, it's encouraging.
This patch only include minor code style improvements.
Comment #15
coltraneTests pass and this looks really good. I just have a couple suggestions.
Minor grammer mistake: "invoke"
Edit: dreditor didn't work right, manually modified the code sections.
Comment #16
banviktor CreditAttribution: banviktor commentedAs @scor is busy, I've extended his patch with the requested features, so this issue won't be blocking the next release. All credits go to @scor !
Also user/logout seems to be the new default logout path, so added that to the list of allowed paths.
Comment #17
coltraneWant to review further but quick nitpick for coding standards:
Bring back newline please, coding standard has ending newline https://www.drupal.org/coding-standards#indenting
Same regarding newline
Comment #18
banviktor CreditAttribution: banviktor commentedGit diff should handle that notification better. The second occurence is actually not valid, that file missed the line feed before the patch. It could have added a "-" to that line.
README.md however did need a newline.
Edit: Also changed time() to REQUEST_TIME :)
Comment #19
gregglesHere is a manual reroll as #18 no longer applied. I'm not always good at doing that, so could someone confirm it looks good? :)