LG-283 Fix password reset links sent to unconfirmed email address#2182
LG-283 Fix password reset links sent to unconfirmed email address#2182
Conversation
brodygov
left a comment
There was a problem hiding this comment.
As written this causes email change confirmations to also be sent to the old address, which allows a user to confirm any email address, even ones they do not control.
The correct behavior here should involve different logic between password reset confirmation tokens (sent to old address) and email change confirmation tokens (sent to new address).
Could you add a test that we are not sending email change confirmation messages to the old address? That would be a big vulnerability if we ever rolled that out.
At some point we also might consider adding a feature to send notification to both the new and old email addresses. Some sites have a way to disavow an email change from the old address as a way to cancel mistakes or fix account takeovers.
|
P.S. It would also be good to find a way to ensure that the message displayed to the user "We sent an email to {email}" accurately reflects the address we really sent the message to. For password resets today we incorrectly tell the user that we sent an email to the old address, and it would be good to ensure that those can't diverge. https://github.com/18F/identity-private/issues/2606 |
ee33c76 to
e06d738
Compare
|
Among the changes with this last PR is the removal of This has been tested with emails generated during each step of our signup and account modification process, namely the following four flows: 1) Signup, 2) Email (account) change, 3) Password (account) change, and 4) Password reset ('forgot' path). To demonstrate when and which emails are generated, beginning from a fresh config:
Returning to a test of the scenario with steps from the original report, from scratch:
Another change that falls out of this, is the use of a Your scrutiny is kindly requested... |
e06d738 to
9a40a75
Compare
brodygov
left a comment
There was a problem hiding this comment.
Looks good, but please add tests that we send email confirmation messages and password reset messages to the correct respective email addresses.
app/mailers/user_mailer.rb
Outdated
There was a problem hiding this comment.
AFAIK the Reply-To header isn't useful unless you want replies to be sent somewhere other than the From header.
There was a problem hiding this comment.
That was actually added for the sake of consistency. As mentioned, our small group of generated emails follows one of two paths: either via our own Rails mailers, or Devise-generated messages. (Both ultimately call mail() in Rails.)
Devise messages include the header by default, and since we're no longer customizing those, it made sense to add it to our own mailers as well, with no discernible cost (and possibly a small boost) to deliverability. Unless we don't like the semantics of a non-reply Reply-To, in which case we would need to again customize the headers. (I'd advise not.)
9a40a75 to
5b603b1
Compare
|
@brodygov Updated, with specs for the two scenarios described. (We have a ton of existing coverage around much of this functionality, but perhaps none quite describing this particular issue.) |
| visit sign_out_url | ||
|
|
||
| click_link t('links.passwords.forgot') | ||
| fill_in 'password_reset_email_form_email', with: user.email |
There was a problem hiding this comment.
This assumes that the user's email hasn't been changed yet, which could potentially change due to a bug. To be safe, what do you think about checking for an explicit email by defining a specific email when creating the user, then filling in the password reset field with that email (the actual string as opposed to user.email), and then verifiying that the email is sent to that string?
**Why**: User could lose account access if password reset link sent to incorrect or inaccessible address **How**: Remove the Devise mail helper initializer added to keep unencrypted email addresses from log files, now superfluous since all job log entries have standardized output via our custom `ActiveJob::Logging::LogSubscriber`
5b603b1 to
075f2d9
Compare
**Why**: User could lose account access if password reset link sent to incorrect or inaccessible address **How**: Remove the Devise mail helper initializer added to keep unencrypted email addresses from log files, now superfluous since all job log entries have standardized output via our custom `ActiveJob::Logging::LogSubscriber`
Added requested (and subsequent) coverage
Why:
Currently password and email address reset confirmation emails are sent
to a newly-added email address prior to validation. This results in a
potential loss of account access, in a scenario described in LG-283.
How:
Remove the use of
unconfirmed_emailfor these messages, sending to theexisting account email address instead.
Specs are passing, and manually (and separately) tested scenarios
included:
This is a small change with a potentially broad impact, so extra scrutiny is recommended.
Question: Is there ever a scenario where an unconfirmed email should be sent a message, versus the currently-confirmed one (for any event)?
Hi! Before submitting your PR for review, and/or before merging it, please
go through the following checklist:
For DB changes, check for missing indexes, check to see if the changes
affect other apps (such as the dashboard), make sure the DB columns in the
various environments are properly populated, coordinate with devops, plan
migrations in separate steps.
For route changes, make sure GET requests don't change state or result in
destructive behavior. GET requests should only result in information being
read, not written.
For encryption changes, make sure it is compatible with data that was
encrypted with the old code.
For secrets changes, make sure to update the S3 secrets bucket with the
new configs in all environments.
Do not disable Rubocop or Reek offenses unless you are absolutely sure
they are false positives. If you're not sure how to fix the offense, please
ask a teammate.
When reading data, write tests for nil values, empty strings,
and invalid formats.
When calling
redirect_toin a controller, use_url, not_path.When adding a new controller that requires the user to be fully
authenticated, make sure to add
before_action :confirm_two_factor_authenticated.When adding user data to the session, use the
user_sessionhelperinstead of the
sessionhelper so the data does not persist beyond the user'ssession.