Invalidate outstanding password reset links when users adjust email addresses

Summary:
Fixes T5506. Depends on D10133. When users remove an email address or change their primary email address, invalidate any outstanding password reset links.

This is a very small security risk, but the current behavior is somewhat surprising, and an attacker could sit on a reset link for up to 24 hours and then use it to re-compromise an account.

Test Plan:
  - Changed primary address and removed addreses.
  - Verified these actions invalidated outstanding one-time login temporary tokens.
  - Tried to use revoked reset links.
  - Revoked normally from new UI panel.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T5506

Differential Revision: https://secure.phabricator.com/D10134
This commit is contained in:
epriestley
2014-08-04 12:04:23 -07:00
parent 30f6405a86
commit e56dc8f299
4 changed files with 62 additions and 8 deletions

View File

@@ -46,7 +46,7 @@ final class PhabricatorAuthRevokeTokenController
if ($request->isDialogFormPost()) { if ($request->isDialogFormPost()) {
foreach ($tokens as $token) { foreach ($tokens as $token) {
$token->setTokenExpires(PhabricatorTime::getNow() - 1)->save(); $token->revokeToken();
} }
return id(new AphrontRedirectResponse())->setURI($panel_uri); return id(new AphrontRedirectResponse())->setURI($panel_uri);
} }

View File

@@ -44,6 +44,30 @@ final class PhabricatorAuthTemporaryToken extends PhabricatorAuthDAO
return false; return false;
} }
public function revokeToken() {
if ($this->isRevocable()) {
$this->setTokenExpires(PhabricatorTime::getNow() - 1)->save();
}
return $this;
}
public static function revokeTokens(
PhabricatorUser $viewer,
array $object_phids,
array $token_types) {
$tokens = id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer($viewer)
->withObjectPHIDs($object_phids)
->withTokenTypes($token_types)
->withExpired(false)
->execute();
foreach ($tokens as $token) {
$token->revokeToken();
}
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */ /* -( PhabricatorPolicyInterface )----------------------------------------- */

View File

@@ -427,6 +427,8 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
$user->endWriteLocking(); $user->endWriteLocking();
$user->saveTransaction(); $user->saveTransaction();
$this->revokePasswordResetLinks($user);
return $this; return $this;
} }
@@ -490,6 +492,9 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
} }
$email->sendNewPrimaryEmail($user); $email->sendNewPrimaryEmail($user);
$this->revokePasswordResetLinks($user);
return $this; return $this;
} }
@@ -575,4 +580,19 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
} }
} }
private function revokePasswordResetLinks(PhabricatorUser $user) {
// Revoke any outstanding password reset links. If an attacker compromises
// an account, changes the email address, and sends themselves a password
// reset link, it could otherwise remain live for a short period of time
// and allow them to compromise the account again later.
PhabricatorAuthTemporaryToken::revokeTokens(
$user,
array($user->getPHID()),
array(
PhabricatorAuthSessionEngine::ONETIME_TEMPORARY_TOKEN_TYPE,
PhabricatorAuthSessionEngine::PASSWORD_TEMPORARY_TOKEN_TYPE,
));
}
} }

View File

@@ -276,9 +276,14 @@ final class PhabricatorSettingsPanelEmailAddresses
->setUser($user) ->setUser($user)
->addHiddenInput('delete', $email_id) ->addHiddenInput('delete', $email_id)
->setTitle(pht("Really delete address '%s'?", $address)) ->setTitle(pht("Really delete address '%s'?", $address))
->appendChild(phutil_tag('p', array(), pht( ->appendParagraph(
'Are you sure you want to delete this address? You will no '. pht(
'longer be able to use it to login.'))) 'Are you sure you want to delete this address? You will no '.
'longer be able to use it to login.'))
->appendParagraph(
pht(
'Note: Removing an email address from your account will invalidate '.
'any outstanding password reset links.'))
->addSubmitButton(pht('Delete')) ->addSubmitButton(pht('Delete'))
->addCancelButton($uri); ->addCancelButton($uri);
@@ -359,10 +364,15 @@ final class PhabricatorSettingsPanelEmailAddresses
->setUser($user) ->setUser($user)
->addHiddenInput('primary', $email_id) ->addHiddenInput('primary', $email_id)
->setTitle(pht('Change primary email address?')) ->setTitle(pht('Change primary email address?'))
->appendChild(phutil_tag('p', array(), pht( ->appendParagraph(
'If you change your primary address, Phabricator will send'. pht(
' all email to %s.', 'If you change your primary address, Phabricator will send all '.
$address))) 'email to %s.',
$address))
->appendParagraph(
pht(
'Note: Changing your primary email address will invalidate any '.
'outstanding password reset links.'))
->addSubmitButton(pht('Change Primary Address')) ->addSubmitButton(pht('Change Primary Address'))
->addCancelButton($uri); ->addCancelButton($uri);