How to prevent password reset from disclosing private email addresses?User registration error : Two different values for password in database?How can I know if JTable->save() is inserting or updating a record?Disable front-end registrators from recving a confirmation emailDisabling Joomla Unique Email FunctionalityLogin user by Username without getting passwordRegister user via external script and a random passwordHow should I register my users without email address?Alerts not appearing on registration pageBreezingForms unique user email validation problemHow to remove username field from the reset password confirmation form?
For the Single Entry Schengen visa, do the microstates (Monaco, San Marino and the Vatican City) count?
How can I more clearly ask people to accomodate for my autism?
How are astronauts in the ISS protected from electric shock?
Find d this ones stumped me help?
What would you do? Different results than what is reported
List of instances where Rambam argues on the Rif
Holding cost vs carrying cost vs storage cost
Is it OK to call company for more details about a job post (not an application)?
Python algorithm that converts array-like data into MathJax
Auto adjust the width of a tcolorbox right part
Wood glue versus epoxy for doweling stripped screw holes
What happened to the SEV instruction on the 6502?
Why are one-word titles so dominant in books, film, and games?
Program to print the multiple occurrence of numbers in a list
Asimov's story where a man's speech contains no information
When are homomorphisms between Banach algebras contractions?
Implement the 2D Hadamard Transform
Meaning of 早口 - fast talker
Is rent considered a debt?
Why do the Romance languages use definite articles, when Latin doesn't?
Why am i getting the wrong IP from DNS lookups
Which 50 amp breaker do I need for my old Eaton panel?
As tourist in China do I have to fear consequences for having publicly liked South Park
What would cause all humans to stop having kids cheerfully, painlessly, voluntarily?
How to prevent password reset from disclosing private email addresses?
User registration error : Two different values for password in database?How can I know if JTable->save() is inserting or updating a record?Disable front-end registrators from recving a confirmation emailDisabling Joomla Unique Email FunctionalityLogin user by Username without getting passwordRegister user via external script and a random passwordHow should I register my users without email address?Alerts not appearing on registration pageBreezingForms unique user email validation problemHow to remove username field from the reset password confirmation form?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;
The "Forgot your password?" password reset form in Joomla 3.x can disclose that an email address is registered with the site. This is a personal privacy violation which is illegal under some privacy laws.
The problem is that the core Joomla function reports two different messages and formats:
- "Reset password failed: Invalid email address" when a
non-registered address is entered into the reset form, and - "An email has been sent to your email address. The email has a verification code, please paste the verification code in the field
below to prove that you are the owner of this account." when a
registered address is entered.
A third party can therefore determine that any email address is registered to and is associated with the site. Email addresses are commonly widely known, and in many cases are in the form Firstname.Lastname@
Can this be corrected with an override, to return the #2 response above regardless of the not/registered status of the email address entered?
If not, what core file(s) need to be changed?
I am not mentioning Username here because I am using a plugin which allows authentication by email address and password instead of Username and password.
Please note! If you are unfamiliar with these specific responses, they are different. #1 is text that appears in a Joomla error box. #2 appears as text at the top of the form. This disclosure problem is not solved by a language file override making the text identical.
joomla-3.x login
New contributor
add a comment
|
The "Forgot your password?" password reset form in Joomla 3.x can disclose that an email address is registered with the site. This is a personal privacy violation which is illegal under some privacy laws.
The problem is that the core Joomla function reports two different messages and formats:
- "Reset password failed: Invalid email address" when a
non-registered address is entered into the reset form, and - "An email has been sent to your email address. The email has a verification code, please paste the verification code in the field
below to prove that you are the owner of this account." when a
registered address is entered.
A third party can therefore determine that any email address is registered to and is associated with the site. Email addresses are commonly widely known, and in many cases are in the form Firstname.Lastname@
Can this be corrected with an override, to return the #2 response above regardless of the not/registered status of the email address entered?
If not, what core file(s) need to be changed?
I am not mentioning Username here because I am using a plugin which allows authentication by email address and password instead of Username and password.
Please note! If you are unfamiliar with these specific responses, they are different. #1 is text that appears in a Joomla error box. #2 appears as text at the top of the form. This disclosure problem is not solved by a language file override making the text identical.
joomla-3.x login
New contributor
I love this phoenix which has risen from the ashes of an earlier difficult question. This is good content. A clear and useful question peppered with very different and insightful answers. This is the best kind of outcome. Lots of knowledge being shared here, good job everyone -- very proud of this community right now.
– mickmackusa♦
2 days ago
I'm delighted with the answers, all which I have read. I have not quite had time to dig in and apply them (disruptive life situation) but they have already served as a educational and useful point which to move forward on. One delay: I'm finally setting up Eclipse on Joomla so I can step through the code and understand the Joomla classes and MVC more clearly. I'll report back this week and also select an answer. Thank for everyone's help, forgiveness for my earlier muddled question and impatience.
– brett
23 hours ago
add a comment
|
The "Forgot your password?" password reset form in Joomla 3.x can disclose that an email address is registered with the site. This is a personal privacy violation which is illegal under some privacy laws.
The problem is that the core Joomla function reports two different messages and formats:
- "Reset password failed: Invalid email address" when a
non-registered address is entered into the reset form, and - "An email has been sent to your email address. The email has a verification code, please paste the verification code in the field
below to prove that you are the owner of this account." when a
registered address is entered.
A third party can therefore determine that any email address is registered to and is associated with the site. Email addresses are commonly widely known, and in many cases are in the form Firstname.Lastname@
Can this be corrected with an override, to return the #2 response above regardless of the not/registered status of the email address entered?
If not, what core file(s) need to be changed?
I am not mentioning Username here because I am using a plugin which allows authentication by email address and password instead of Username and password.
Please note! If you are unfamiliar with these specific responses, they are different. #1 is text that appears in a Joomla error box. #2 appears as text at the top of the form. This disclosure problem is not solved by a language file override making the text identical.
joomla-3.x login
New contributor
The "Forgot your password?" password reset form in Joomla 3.x can disclose that an email address is registered with the site. This is a personal privacy violation which is illegal under some privacy laws.
The problem is that the core Joomla function reports two different messages and formats:
- "Reset password failed: Invalid email address" when a
non-registered address is entered into the reset form, and - "An email has been sent to your email address. The email has a verification code, please paste the verification code in the field
below to prove that you are the owner of this account." when a
registered address is entered.
A third party can therefore determine that any email address is registered to and is associated with the site. Email addresses are commonly widely known, and in many cases are in the form Firstname.Lastname@
Can this be corrected with an override, to return the #2 response above regardless of the not/registered status of the email address entered?
If not, what core file(s) need to be changed?
I am not mentioning Username here because I am using a plugin which allows authentication by email address and password instead of Username and password.
Please note! If you are unfamiliar with these specific responses, they are different. #1 is text that appears in a Joomla error box. #2 appears as text at the top of the form. This disclosure problem is not solved by a language file override making the text identical.
joomla-3.x login
joomla-3.x login
New contributor
New contributor
New contributor
asked Oct 12 at 21:56
brettbrett
164 bronze badges
164 bronze badges
New contributor
New contributor
I love this phoenix which has risen from the ashes of an earlier difficult question. This is good content. A clear and useful question peppered with very different and insightful answers. This is the best kind of outcome. Lots of knowledge being shared here, good job everyone -- very proud of this community right now.
– mickmackusa♦
2 days ago
I'm delighted with the answers, all which I have read. I have not quite had time to dig in and apply them (disruptive life situation) but they have already served as a educational and useful point which to move forward on. One delay: I'm finally setting up Eclipse on Joomla so I can step through the code and understand the Joomla classes and MVC more clearly. I'll report back this week and also select an answer. Thank for everyone's help, forgiveness for my earlier muddled question and impatience.
– brett
23 hours ago
add a comment
|
I love this phoenix which has risen from the ashes of an earlier difficult question. This is good content. A clear and useful question peppered with very different and insightful answers. This is the best kind of outcome. Lots of knowledge being shared here, good job everyone -- very proud of this community right now.
– mickmackusa♦
2 days ago
I'm delighted with the answers, all which I have read. I have not quite had time to dig in and apply them (disruptive life situation) but they have already served as a educational and useful point which to move forward on. One delay: I'm finally setting up Eclipse on Joomla so I can step through the code and understand the Joomla classes and MVC more clearly. I'll report back this week and also select an answer. Thank for everyone's help, forgiveness for my earlier muddled question and impatience.
– brett
23 hours ago
I love this phoenix which has risen from the ashes of an earlier difficult question. This is good content. A clear and useful question peppered with very different and insightful answers. This is the best kind of outcome. Lots of knowledge being shared here, good job everyone -- very proud of this community right now.
– mickmackusa♦
2 days ago
I love this phoenix which has risen from the ashes of an earlier difficult question. This is good content. A clear and useful question peppered with very different and insightful answers. This is the best kind of outcome. Lots of knowledge being shared here, good job everyone -- very proud of this community right now.
– mickmackusa♦
2 days ago
I'm delighted with the answers, all which I have read. I have not quite had time to dig in and apply them (disruptive life situation) but they have already served as a educational and useful point which to move forward on. One delay: I'm finally setting up Eclipse on Joomla so I can step through the code and understand the Joomla classes and MVC more clearly. I'll report back this week and also select an answer. Thank for everyone's help, forgiveness for my earlier muddled question and impatience.
– brett
23 hours ago
I'm delighted with the answers, all which I have read. I have not quite had time to dig in and apply them (disruptive life situation) but they have already served as a educational and useful point which to move forward on. One delay: I'm finally setting up Eclipse on Joomla so I can step through the code and understand the Joomla classes and MVC more clearly. I'll report back this week and also select an answer. Thank for everyone's help, forgiveness for my earlier muddled question and impatience.
– brett
23 hours ago
add a comment
|
3 Answers
3
active
oldest
votes
Great Question Brett. This is one of the only core hacks I've ever had to make. If someone has a better solution then please post it here.
In this file:
https://github.com/joomla/joomla-cms/blob/staging/components/com_users/models/reset.php
In the public function processResetRequest($data)
Where it checks to see if the user exists just return true early. This thus stops the email and reset process but also shows the regular success message to the user.
Original lines 398-404
// Check for a user.
if (empty($userId))
$this->setError(JText::_('COM_USERS_INVALID_EMAIL'));
return false;
Changed to:
// Check for a user.
if (empty($userId))
/* === BEGIN CORE HACK === */
return true;
/* === END CORE HACK ===== */
$this->setError(JText::_('COM_USERS_INVALID_EMAIL'));
return false;
Thanks for a super clear answer James. Unfortunately I'm still getting the Joomla error text box vs in-form status messages. Looking at the code you pointed me to (thanks!) I don't see why it wouldn't work at this late hour. Maybe something related to the auth-email plugin I am using changed something related? I will look at this more closely tomorrow and report my findings. BTW, I like your clear commenting, "BEGIN CORE HACK"
– brett
Oct 13 at 3:19
Note that if a nonexistent user takes a different amount of time to return, it will still be possible to tell if the email address is registered or not, even if the response message is identical. Also if there's some check when you register that tells you the email address is already taken or not, then this is pointless.
– Kat
Oct 13 at 15:31
add a comment
|
To avoid a core hack there are two approaches I would suggest you could either create your own Model that would extend UserModelReset
so that you can insert a fake user id when a valid one is not found.
Or create an override for /com_users/view/reset/tmpl/default.php and replace line 24 to not call reset.request in the subcontroller reset.php but some code of your own.
<form id="user-registration" action="<?php echo JRoute::_('index.php?option=com_users&task=reset.request'); ?>" method="post" class="form-validate form-horizontal well">
Or if the plugin you mention is something you can edit then I would suggest you do your own check if the user exists in the com_user table and if not then pass a valid but fake userid to the regular processing, just don't allow a non-existent user to be passed. Not knowing when the plugin gets involved, I can't be sure this is a valid option for you, but would be easiest and cleanest way to do it.
If you follow the process of a normal password reset then you can see what is happening and why the code hack described by @jamesgarret is not working for you and you aren't getting to the final page displayed with the 'email sent' message. I would guess that your Plugin is calling processResetRequest
directly and not going through the subcontroller reset.request.
As mentioned above default.php
calls the subcontrolelr reset.php
and function request
. function request
in turn calls processResetRequest
in com_user/models/reset.php
If you read what is going on processResetRequest
you can see that a database call for the user email address is made and that variable of $userId is returned at line 389.
As per @jamesgarret answer at line 399 a check is done for an empty $userId
and it is at this point that you do NOT want have an empty $userId
. If you used the core hack from @jamesgarret with the normal processing then return true
gets you back to reset.request
but if your Plugin is what called processResetRequest
then you need to handle the redirect to the correct page yourself.
If you haven't already checked and passed a fake user id via your plugin then at line 401 you need to create a valid user id and give it to $userId
so the processing can continue with valid User Id.
(changing line 401 would be a core hack or in an extended processReserRequest)
You have to create a fake user id in your com_user table that isn't a super user and has a valid email address that you can automatically discard when it is received by your mail server/account.
The reason you need this fake user id is so that processing can complete, an email is sent and you get to the bottom of the processResetRequest
so that you get returned to the request
function in the reset
subcontroller. This is what redirects you to com_user/views/reset/tmpl/reset.php
which is the screen you want with the right message that an email has been sent and everything looks genuine.
Incidentally the message you want to appear
"An email has been sent to your email address. The email has a
verification code, please paste the verification code in the field
below to prove that you are the owner of this account."
comes from com_users/models/forms/reset_confirm.xml
and is a fieldset label at line 3.
<fieldset name="default" label="COM_USERS_RESET_CONFIRM_LABEL">
add a comment
|
You can use a plugin onAfterRoute
event to override controller tasks in a sense. It's not perfect but it beats core hacking. The following example mimics UsersControllerReset:request()
but redirects to confirmation page even when model returns false
.
defined('_JEXEC') or die;
use JoomlaCMSLanguageText;
use JoomlaCMSPluginCMSPlugin;
use JoomlaCMSRouterRoute;
class PlgSystemExample extends CMSPlugin
protected $app;
public function onAfterRoute()
// Check that we are performing the correct task.
if ($this->app->input->get('option') === 'com_users' && $this->app->input->get('task') === 'reset.request')
$this->request();
protected function request()
// Check the request token.
if (!$this->app->getSession()->checkToken('post'))
$this->app->enqueueMessage(Text::_('JINVALID_TOKEN_NOTICE'), 'error');
$this->app->redirect(Route::_('index.php?option=com_users&view=reset', false));
$option = $this->app->input->get('option');
// Define component paths. The model may need them.
if (!defined('JPATH_COMPONENT'))
define('JPATH_COMPONENT', JPATH_BASE . '/components/' . $option);
if (!defined('JPATH_COMPONENT_SITE'))
define('JPATH_COMPONENT_SITE', JPATH_SITE . '/components/' . $option);
if (!defined('JPATH_COMPONENT_ADMINISTRATOR'))
define('JPATH_COMPONENT_ADMINISTRATOR', JPATH_ADMINISTRATOR . '/components/' . $option);
// Load com_users language files.
$this->app->getLanguage()->load('com_users');
// Register com_users models.
JModelLegacy::addIncludePath(JPATH_SITE . '/components/com_users/models', 'UsersModel');
// Fetch the model.
$model = JModelLegacy::getInstance('Reset', 'UsersModel');
// Submit the password reset request.
$data = $this->app->input->post->get('jform', array(), 'array');
$return = $model->processResetRequest($data);
// Check for a hard error. It can occur when sending mail fails.
if ($return instanceof Exception)
// Get the error message to display.
if ($this->app->get('error_reporting'))
$message = $return->getMessage();
else
$message = Text::_('COM_USERS_RESET_REQUEST_ERROR');
// Go back to the request form.
$this->app->enqueueMessage($message, 'error');
$this->app->redirect(Route::_('index.php?option=com_users&view=reset', false));
// Redirect to confirmation page.
$this->app->redirect(Route::_('index.php?option=com_users&view=reset&layout=confirm', false));
This would be a great plugin if someone could throw together in GitHub or whatnot so basic users could download/install.
– YellowWebMonkey
22 hours ago
add a comment
|
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "555"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
noCode: true, onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
brett is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fjoomla.stackexchange.com%2fquestions%2f26252%2fhow-to-prevent-password-reset-from-disclosing-private-email-addresses%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
Great Question Brett. This is one of the only core hacks I've ever had to make. If someone has a better solution then please post it here.
In this file:
https://github.com/joomla/joomla-cms/blob/staging/components/com_users/models/reset.php
In the public function processResetRequest($data)
Where it checks to see if the user exists just return true early. This thus stops the email and reset process but also shows the regular success message to the user.
Original lines 398-404
// Check for a user.
if (empty($userId))
$this->setError(JText::_('COM_USERS_INVALID_EMAIL'));
return false;
Changed to:
// Check for a user.
if (empty($userId))
/* === BEGIN CORE HACK === */
return true;
/* === END CORE HACK ===== */
$this->setError(JText::_('COM_USERS_INVALID_EMAIL'));
return false;
Thanks for a super clear answer James. Unfortunately I'm still getting the Joomla error text box vs in-form status messages. Looking at the code you pointed me to (thanks!) I don't see why it wouldn't work at this late hour. Maybe something related to the auth-email plugin I am using changed something related? I will look at this more closely tomorrow and report my findings. BTW, I like your clear commenting, "BEGIN CORE HACK"
– brett
Oct 13 at 3:19
Note that if a nonexistent user takes a different amount of time to return, it will still be possible to tell if the email address is registered or not, even if the response message is identical. Also if there's some check when you register that tells you the email address is already taken or not, then this is pointless.
– Kat
Oct 13 at 15:31
add a comment
|
Great Question Brett. This is one of the only core hacks I've ever had to make. If someone has a better solution then please post it here.
In this file:
https://github.com/joomla/joomla-cms/blob/staging/components/com_users/models/reset.php
In the public function processResetRequest($data)
Where it checks to see if the user exists just return true early. This thus stops the email and reset process but also shows the regular success message to the user.
Original lines 398-404
// Check for a user.
if (empty($userId))
$this->setError(JText::_('COM_USERS_INVALID_EMAIL'));
return false;
Changed to:
// Check for a user.
if (empty($userId))
/* === BEGIN CORE HACK === */
return true;
/* === END CORE HACK ===== */
$this->setError(JText::_('COM_USERS_INVALID_EMAIL'));
return false;
Thanks for a super clear answer James. Unfortunately I'm still getting the Joomla error text box vs in-form status messages. Looking at the code you pointed me to (thanks!) I don't see why it wouldn't work at this late hour. Maybe something related to the auth-email plugin I am using changed something related? I will look at this more closely tomorrow and report my findings. BTW, I like your clear commenting, "BEGIN CORE HACK"
– brett
Oct 13 at 3:19
Note that if a nonexistent user takes a different amount of time to return, it will still be possible to tell if the email address is registered or not, even if the response message is identical. Also if there's some check when you register that tells you the email address is already taken or not, then this is pointless.
– Kat
Oct 13 at 15:31
add a comment
|
Great Question Brett. This is one of the only core hacks I've ever had to make. If someone has a better solution then please post it here.
In this file:
https://github.com/joomla/joomla-cms/blob/staging/components/com_users/models/reset.php
In the public function processResetRequest($data)
Where it checks to see if the user exists just return true early. This thus stops the email and reset process but also shows the regular success message to the user.
Original lines 398-404
// Check for a user.
if (empty($userId))
$this->setError(JText::_('COM_USERS_INVALID_EMAIL'));
return false;
Changed to:
// Check for a user.
if (empty($userId))
/* === BEGIN CORE HACK === */
return true;
/* === END CORE HACK ===== */
$this->setError(JText::_('COM_USERS_INVALID_EMAIL'));
return false;
Great Question Brett. This is one of the only core hacks I've ever had to make. If someone has a better solution then please post it here.
In this file:
https://github.com/joomla/joomla-cms/blob/staging/components/com_users/models/reset.php
In the public function processResetRequest($data)
Where it checks to see if the user exists just return true early. This thus stops the email and reset process but also shows the regular success message to the user.
Original lines 398-404
// Check for a user.
if (empty($userId))
$this->setError(JText::_('COM_USERS_INVALID_EMAIL'));
return false;
Changed to:
// Check for a user.
if (empty($userId))
/* === BEGIN CORE HACK === */
return true;
/* === END CORE HACK ===== */
$this->setError(JText::_('COM_USERS_INVALID_EMAIL'));
return false;
edited Oct 13 at 1:49
answered Oct 13 at 1:44
jamesgarrettjamesgarrett
2,6341 gold badge5 silver badges13 bronze badges
2,6341 gold badge5 silver badges13 bronze badges
Thanks for a super clear answer James. Unfortunately I'm still getting the Joomla error text box vs in-form status messages. Looking at the code you pointed me to (thanks!) I don't see why it wouldn't work at this late hour. Maybe something related to the auth-email plugin I am using changed something related? I will look at this more closely tomorrow and report my findings. BTW, I like your clear commenting, "BEGIN CORE HACK"
– brett
Oct 13 at 3:19
Note that if a nonexistent user takes a different amount of time to return, it will still be possible to tell if the email address is registered or not, even if the response message is identical. Also if there's some check when you register that tells you the email address is already taken or not, then this is pointless.
– Kat
Oct 13 at 15:31
add a comment
|
Thanks for a super clear answer James. Unfortunately I'm still getting the Joomla error text box vs in-form status messages. Looking at the code you pointed me to (thanks!) I don't see why it wouldn't work at this late hour. Maybe something related to the auth-email plugin I am using changed something related? I will look at this more closely tomorrow and report my findings. BTW, I like your clear commenting, "BEGIN CORE HACK"
– brett
Oct 13 at 3:19
Note that if a nonexistent user takes a different amount of time to return, it will still be possible to tell if the email address is registered or not, even if the response message is identical. Also if there's some check when you register that tells you the email address is already taken or not, then this is pointless.
– Kat
Oct 13 at 15:31
Thanks for a super clear answer James. Unfortunately I'm still getting the Joomla error text box vs in-form status messages. Looking at the code you pointed me to (thanks!) I don't see why it wouldn't work at this late hour. Maybe something related to the auth-email plugin I am using changed something related? I will look at this more closely tomorrow and report my findings. BTW, I like your clear commenting, "BEGIN CORE HACK"
– brett
Oct 13 at 3:19
Thanks for a super clear answer James. Unfortunately I'm still getting the Joomla error text box vs in-form status messages. Looking at the code you pointed me to (thanks!) I don't see why it wouldn't work at this late hour. Maybe something related to the auth-email plugin I am using changed something related? I will look at this more closely tomorrow and report my findings. BTW, I like your clear commenting, "BEGIN CORE HACK"
– brett
Oct 13 at 3:19
Note that if a nonexistent user takes a different amount of time to return, it will still be possible to tell if the email address is registered or not, even if the response message is identical. Also if there's some check when you register that tells you the email address is already taken or not, then this is pointless.
– Kat
Oct 13 at 15:31
Note that if a nonexistent user takes a different amount of time to return, it will still be possible to tell if the email address is registered or not, even if the response message is identical. Also if there's some check when you register that tells you the email address is already taken or not, then this is pointless.
– Kat
Oct 13 at 15:31
add a comment
|
To avoid a core hack there are two approaches I would suggest you could either create your own Model that would extend UserModelReset
so that you can insert a fake user id when a valid one is not found.
Or create an override for /com_users/view/reset/tmpl/default.php and replace line 24 to not call reset.request in the subcontroller reset.php but some code of your own.
<form id="user-registration" action="<?php echo JRoute::_('index.php?option=com_users&task=reset.request'); ?>" method="post" class="form-validate form-horizontal well">
Or if the plugin you mention is something you can edit then I would suggest you do your own check if the user exists in the com_user table and if not then pass a valid but fake userid to the regular processing, just don't allow a non-existent user to be passed. Not knowing when the plugin gets involved, I can't be sure this is a valid option for you, but would be easiest and cleanest way to do it.
If you follow the process of a normal password reset then you can see what is happening and why the code hack described by @jamesgarret is not working for you and you aren't getting to the final page displayed with the 'email sent' message. I would guess that your Plugin is calling processResetRequest
directly and not going through the subcontroller reset.request.
As mentioned above default.php
calls the subcontrolelr reset.php
and function request
. function request
in turn calls processResetRequest
in com_user/models/reset.php
If you read what is going on processResetRequest
you can see that a database call for the user email address is made and that variable of $userId is returned at line 389.
As per @jamesgarret answer at line 399 a check is done for an empty $userId
and it is at this point that you do NOT want have an empty $userId
. If you used the core hack from @jamesgarret with the normal processing then return true
gets you back to reset.request
but if your Plugin is what called processResetRequest
then you need to handle the redirect to the correct page yourself.
If you haven't already checked and passed a fake user id via your plugin then at line 401 you need to create a valid user id and give it to $userId
so the processing can continue with valid User Id.
(changing line 401 would be a core hack or in an extended processReserRequest)
You have to create a fake user id in your com_user table that isn't a super user and has a valid email address that you can automatically discard when it is received by your mail server/account.
The reason you need this fake user id is so that processing can complete, an email is sent and you get to the bottom of the processResetRequest
so that you get returned to the request
function in the reset
subcontroller. This is what redirects you to com_user/views/reset/tmpl/reset.php
which is the screen you want with the right message that an email has been sent and everything looks genuine.
Incidentally the message you want to appear
"An email has been sent to your email address. The email has a
verification code, please paste the verification code in the field
below to prove that you are the owner of this account."
comes from com_users/models/forms/reset_confirm.xml
and is a fieldset label at line 3.
<fieldset name="default" label="COM_USERS_RESET_CONFIRM_LABEL">
add a comment
|
To avoid a core hack there are two approaches I would suggest you could either create your own Model that would extend UserModelReset
so that you can insert a fake user id when a valid one is not found.
Or create an override for /com_users/view/reset/tmpl/default.php and replace line 24 to not call reset.request in the subcontroller reset.php but some code of your own.
<form id="user-registration" action="<?php echo JRoute::_('index.php?option=com_users&task=reset.request'); ?>" method="post" class="form-validate form-horizontal well">
Or if the plugin you mention is something you can edit then I would suggest you do your own check if the user exists in the com_user table and if not then pass a valid but fake userid to the regular processing, just don't allow a non-existent user to be passed. Not knowing when the plugin gets involved, I can't be sure this is a valid option for you, but would be easiest and cleanest way to do it.
If you follow the process of a normal password reset then you can see what is happening and why the code hack described by @jamesgarret is not working for you and you aren't getting to the final page displayed with the 'email sent' message. I would guess that your Plugin is calling processResetRequest
directly and not going through the subcontroller reset.request.
As mentioned above default.php
calls the subcontrolelr reset.php
and function request
. function request
in turn calls processResetRequest
in com_user/models/reset.php
If you read what is going on processResetRequest
you can see that a database call for the user email address is made and that variable of $userId is returned at line 389.
As per @jamesgarret answer at line 399 a check is done for an empty $userId
and it is at this point that you do NOT want have an empty $userId
. If you used the core hack from @jamesgarret with the normal processing then return true
gets you back to reset.request
but if your Plugin is what called processResetRequest
then you need to handle the redirect to the correct page yourself.
If you haven't already checked and passed a fake user id via your plugin then at line 401 you need to create a valid user id and give it to $userId
so the processing can continue with valid User Id.
(changing line 401 would be a core hack or in an extended processReserRequest)
You have to create a fake user id in your com_user table that isn't a super user and has a valid email address that you can automatically discard when it is received by your mail server/account.
The reason you need this fake user id is so that processing can complete, an email is sent and you get to the bottom of the processResetRequest
so that you get returned to the request
function in the reset
subcontroller. This is what redirects you to com_user/views/reset/tmpl/reset.php
which is the screen you want with the right message that an email has been sent and everything looks genuine.
Incidentally the message you want to appear
"An email has been sent to your email address. The email has a
verification code, please paste the verification code in the field
below to prove that you are the owner of this account."
comes from com_users/models/forms/reset_confirm.xml
and is a fieldset label at line 3.
<fieldset name="default" label="COM_USERS_RESET_CONFIRM_LABEL">
add a comment
|
To avoid a core hack there are two approaches I would suggest you could either create your own Model that would extend UserModelReset
so that you can insert a fake user id when a valid one is not found.
Or create an override for /com_users/view/reset/tmpl/default.php and replace line 24 to not call reset.request in the subcontroller reset.php but some code of your own.
<form id="user-registration" action="<?php echo JRoute::_('index.php?option=com_users&task=reset.request'); ?>" method="post" class="form-validate form-horizontal well">
Or if the plugin you mention is something you can edit then I would suggest you do your own check if the user exists in the com_user table and if not then pass a valid but fake userid to the regular processing, just don't allow a non-existent user to be passed. Not knowing when the plugin gets involved, I can't be sure this is a valid option for you, but would be easiest and cleanest way to do it.
If you follow the process of a normal password reset then you can see what is happening and why the code hack described by @jamesgarret is not working for you and you aren't getting to the final page displayed with the 'email sent' message. I would guess that your Plugin is calling processResetRequest
directly and not going through the subcontroller reset.request.
As mentioned above default.php
calls the subcontrolelr reset.php
and function request
. function request
in turn calls processResetRequest
in com_user/models/reset.php
If you read what is going on processResetRequest
you can see that a database call for the user email address is made and that variable of $userId is returned at line 389.
As per @jamesgarret answer at line 399 a check is done for an empty $userId
and it is at this point that you do NOT want have an empty $userId
. If you used the core hack from @jamesgarret with the normal processing then return true
gets you back to reset.request
but if your Plugin is what called processResetRequest
then you need to handle the redirect to the correct page yourself.
If you haven't already checked and passed a fake user id via your plugin then at line 401 you need to create a valid user id and give it to $userId
so the processing can continue with valid User Id.
(changing line 401 would be a core hack or in an extended processReserRequest)
You have to create a fake user id in your com_user table that isn't a super user and has a valid email address that you can automatically discard when it is received by your mail server/account.
The reason you need this fake user id is so that processing can complete, an email is sent and you get to the bottom of the processResetRequest
so that you get returned to the request
function in the reset
subcontroller. This is what redirects you to com_user/views/reset/tmpl/reset.php
which is the screen you want with the right message that an email has been sent and everything looks genuine.
Incidentally the message you want to appear
"An email has been sent to your email address. The email has a
verification code, please paste the verification code in the field
below to prove that you are the owner of this account."
comes from com_users/models/forms/reset_confirm.xml
and is a fieldset label at line 3.
<fieldset name="default" label="COM_USERS_RESET_CONFIRM_LABEL">
To avoid a core hack there are two approaches I would suggest you could either create your own Model that would extend UserModelReset
so that you can insert a fake user id when a valid one is not found.
Or create an override for /com_users/view/reset/tmpl/default.php and replace line 24 to not call reset.request in the subcontroller reset.php but some code of your own.
<form id="user-registration" action="<?php echo JRoute::_('index.php?option=com_users&task=reset.request'); ?>" method="post" class="form-validate form-horizontal well">
Or if the plugin you mention is something you can edit then I would suggest you do your own check if the user exists in the com_user table and if not then pass a valid but fake userid to the regular processing, just don't allow a non-existent user to be passed. Not knowing when the plugin gets involved, I can't be sure this is a valid option for you, but would be easiest and cleanest way to do it.
If you follow the process of a normal password reset then you can see what is happening and why the code hack described by @jamesgarret is not working for you and you aren't getting to the final page displayed with the 'email sent' message. I would guess that your Plugin is calling processResetRequest
directly and not going through the subcontroller reset.request.
As mentioned above default.php
calls the subcontrolelr reset.php
and function request
. function request
in turn calls processResetRequest
in com_user/models/reset.php
If you read what is going on processResetRequest
you can see that a database call for the user email address is made and that variable of $userId is returned at line 389.
As per @jamesgarret answer at line 399 a check is done for an empty $userId
and it is at this point that you do NOT want have an empty $userId
. If you used the core hack from @jamesgarret with the normal processing then return true
gets you back to reset.request
but if your Plugin is what called processResetRequest
then you need to handle the redirect to the correct page yourself.
If you haven't already checked and passed a fake user id via your plugin then at line 401 you need to create a valid user id and give it to $userId
so the processing can continue with valid User Id.
(changing line 401 would be a core hack or in an extended processReserRequest)
You have to create a fake user id in your com_user table that isn't a super user and has a valid email address that you can automatically discard when it is received by your mail server/account.
The reason you need this fake user id is so that processing can complete, an email is sent and you get to the bottom of the processResetRequest
so that you get returned to the request
function in the reset
subcontroller. This is what redirects you to com_user/views/reset/tmpl/reset.php
which is the screen you want with the right message that an email has been sent and everything looks genuine.
Incidentally the message you want to appear
"An email has been sent to your email address. The email has a
verification code, please paste the verification code in the field
below to prove that you are the owner of this account."
comes from com_users/models/forms/reset_confirm.xml
and is a fieldset label at line 3.
<fieldset name="default" label="COM_USERS_RESET_CONFIRM_LABEL">
answered Oct 13 at 13:09
IrataIrata
6421 silver badge9 bronze badges
6421 silver badge9 bronze badges
add a comment
|
add a comment
|
You can use a plugin onAfterRoute
event to override controller tasks in a sense. It's not perfect but it beats core hacking. The following example mimics UsersControllerReset:request()
but redirects to confirmation page even when model returns false
.
defined('_JEXEC') or die;
use JoomlaCMSLanguageText;
use JoomlaCMSPluginCMSPlugin;
use JoomlaCMSRouterRoute;
class PlgSystemExample extends CMSPlugin
protected $app;
public function onAfterRoute()
// Check that we are performing the correct task.
if ($this->app->input->get('option') === 'com_users' && $this->app->input->get('task') === 'reset.request')
$this->request();
protected function request()
// Check the request token.
if (!$this->app->getSession()->checkToken('post'))
$this->app->enqueueMessage(Text::_('JINVALID_TOKEN_NOTICE'), 'error');
$this->app->redirect(Route::_('index.php?option=com_users&view=reset', false));
$option = $this->app->input->get('option');
// Define component paths. The model may need them.
if (!defined('JPATH_COMPONENT'))
define('JPATH_COMPONENT', JPATH_BASE . '/components/' . $option);
if (!defined('JPATH_COMPONENT_SITE'))
define('JPATH_COMPONENT_SITE', JPATH_SITE . '/components/' . $option);
if (!defined('JPATH_COMPONENT_ADMINISTRATOR'))
define('JPATH_COMPONENT_ADMINISTRATOR', JPATH_ADMINISTRATOR . '/components/' . $option);
// Load com_users language files.
$this->app->getLanguage()->load('com_users');
// Register com_users models.
JModelLegacy::addIncludePath(JPATH_SITE . '/components/com_users/models', 'UsersModel');
// Fetch the model.
$model = JModelLegacy::getInstance('Reset', 'UsersModel');
// Submit the password reset request.
$data = $this->app->input->post->get('jform', array(), 'array');
$return = $model->processResetRequest($data);
// Check for a hard error. It can occur when sending mail fails.
if ($return instanceof Exception)
// Get the error message to display.
if ($this->app->get('error_reporting'))
$message = $return->getMessage();
else
$message = Text::_('COM_USERS_RESET_REQUEST_ERROR');
// Go back to the request form.
$this->app->enqueueMessage($message, 'error');
$this->app->redirect(Route::_('index.php?option=com_users&view=reset', false));
// Redirect to confirmation page.
$this->app->redirect(Route::_('index.php?option=com_users&view=reset&layout=confirm', false));
This would be a great plugin if someone could throw together in GitHub or whatnot so basic users could download/install.
– YellowWebMonkey
22 hours ago
add a comment
|
You can use a plugin onAfterRoute
event to override controller tasks in a sense. It's not perfect but it beats core hacking. The following example mimics UsersControllerReset:request()
but redirects to confirmation page even when model returns false
.
defined('_JEXEC') or die;
use JoomlaCMSLanguageText;
use JoomlaCMSPluginCMSPlugin;
use JoomlaCMSRouterRoute;
class PlgSystemExample extends CMSPlugin
protected $app;
public function onAfterRoute()
// Check that we are performing the correct task.
if ($this->app->input->get('option') === 'com_users' && $this->app->input->get('task') === 'reset.request')
$this->request();
protected function request()
// Check the request token.
if (!$this->app->getSession()->checkToken('post'))
$this->app->enqueueMessage(Text::_('JINVALID_TOKEN_NOTICE'), 'error');
$this->app->redirect(Route::_('index.php?option=com_users&view=reset', false));
$option = $this->app->input->get('option');
// Define component paths. The model may need them.
if (!defined('JPATH_COMPONENT'))
define('JPATH_COMPONENT', JPATH_BASE . '/components/' . $option);
if (!defined('JPATH_COMPONENT_SITE'))
define('JPATH_COMPONENT_SITE', JPATH_SITE . '/components/' . $option);
if (!defined('JPATH_COMPONENT_ADMINISTRATOR'))
define('JPATH_COMPONENT_ADMINISTRATOR', JPATH_ADMINISTRATOR . '/components/' . $option);
// Load com_users language files.
$this->app->getLanguage()->load('com_users');
// Register com_users models.
JModelLegacy::addIncludePath(JPATH_SITE . '/components/com_users/models', 'UsersModel');
// Fetch the model.
$model = JModelLegacy::getInstance('Reset', 'UsersModel');
// Submit the password reset request.
$data = $this->app->input->post->get('jform', array(), 'array');
$return = $model->processResetRequest($data);
// Check for a hard error. It can occur when sending mail fails.
if ($return instanceof Exception)
// Get the error message to display.
if ($this->app->get('error_reporting'))
$message = $return->getMessage();
else
$message = Text::_('COM_USERS_RESET_REQUEST_ERROR');
// Go back to the request form.
$this->app->enqueueMessage($message, 'error');
$this->app->redirect(Route::_('index.php?option=com_users&view=reset', false));
// Redirect to confirmation page.
$this->app->redirect(Route::_('index.php?option=com_users&view=reset&layout=confirm', false));
This would be a great plugin if someone could throw together in GitHub or whatnot so basic users could download/install.
– YellowWebMonkey
22 hours ago
add a comment
|
You can use a plugin onAfterRoute
event to override controller tasks in a sense. It's not perfect but it beats core hacking. The following example mimics UsersControllerReset:request()
but redirects to confirmation page even when model returns false
.
defined('_JEXEC') or die;
use JoomlaCMSLanguageText;
use JoomlaCMSPluginCMSPlugin;
use JoomlaCMSRouterRoute;
class PlgSystemExample extends CMSPlugin
protected $app;
public function onAfterRoute()
// Check that we are performing the correct task.
if ($this->app->input->get('option') === 'com_users' && $this->app->input->get('task') === 'reset.request')
$this->request();
protected function request()
// Check the request token.
if (!$this->app->getSession()->checkToken('post'))
$this->app->enqueueMessage(Text::_('JINVALID_TOKEN_NOTICE'), 'error');
$this->app->redirect(Route::_('index.php?option=com_users&view=reset', false));
$option = $this->app->input->get('option');
// Define component paths. The model may need them.
if (!defined('JPATH_COMPONENT'))
define('JPATH_COMPONENT', JPATH_BASE . '/components/' . $option);
if (!defined('JPATH_COMPONENT_SITE'))
define('JPATH_COMPONENT_SITE', JPATH_SITE . '/components/' . $option);
if (!defined('JPATH_COMPONENT_ADMINISTRATOR'))
define('JPATH_COMPONENT_ADMINISTRATOR', JPATH_ADMINISTRATOR . '/components/' . $option);
// Load com_users language files.
$this->app->getLanguage()->load('com_users');
// Register com_users models.
JModelLegacy::addIncludePath(JPATH_SITE . '/components/com_users/models', 'UsersModel');
// Fetch the model.
$model = JModelLegacy::getInstance('Reset', 'UsersModel');
// Submit the password reset request.
$data = $this->app->input->post->get('jform', array(), 'array');
$return = $model->processResetRequest($data);
// Check for a hard error. It can occur when sending mail fails.
if ($return instanceof Exception)
// Get the error message to display.
if ($this->app->get('error_reporting'))
$message = $return->getMessage();
else
$message = Text::_('COM_USERS_RESET_REQUEST_ERROR');
// Go back to the request form.
$this->app->enqueueMessage($message, 'error');
$this->app->redirect(Route::_('index.php?option=com_users&view=reset', false));
// Redirect to confirmation page.
$this->app->redirect(Route::_('index.php?option=com_users&view=reset&layout=confirm', false));
You can use a plugin onAfterRoute
event to override controller tasks in a sense. It's not perfect but it beats core hacking. The following example mimics UsersControllerReset:request()
but redirects to confirmation page even when model returns false
.
defined('_JEXEC') or die;
use JoomlaCMSLanguageText;
use JoomlaCMSPluginCMSPlugin;
use JoomlaCMSRouterRoute;
class PlgSystemExample extends CMSPlugin
protected $app;
public function onAfterRoute()
// Check that we are performing the correct task.
if ($this->app->input->get('option') === 'com_users' && $this->app->input->get('task') === 'reset.request')
$this->request();
protected function request()
// Check the request token.
if (!$this->app->getSession()->checkToken('post'))
$this->app->enqueueMessage(Text::_('JINVALID_TOKEN_NOTICE'), 'error');
$this->app->redirect(Route::_('index.php?option=com_users&view=reset', false));
$option = $this->app->input->get('option');
// Define component paths. The model may need them.
if (!defined('JPATH_COMPONENT'))
define('JPATH_COMPONENT', JPATH_BASE . '/components/' . $option);
if (!defined('JPATH_COMPONENT_SITE'))
define('JPATH_COMPONENT_SITE', JPATH_SITE . '/components/' . $option);
if (!defined('JPATH_COMPONENT_ADMINISTRATOR'))
define('JPATH_COMPONENT_ADMINISTRATOR', JPATH_ADMINISTRATOR . '/components/' . $option);
// Load com_users language files.
$this->app->getLanguage()->load('com_users');
// Register com_users models.
JModelLegacy::addIncludePath(JPATH_SITE . '/components/com_users/models', 'UsersModel');
// Fetch the model.
$model = JModelLegacy::getInstance('Reset', 'UsersModel');
// Submit the password reset request.
$data = $this->app->input->post->get('jform', array(), 'array');
$return = $model->processResetRequest($data);
// Check for a hard error. It can occur when sending mail fails.
if ($return instanceof Exception)
// Get the error message to display.
if ($this->app->get('error_reporting'))
$message = $return->getMessage();
else
$message = Text::_('COM_USERS_RESET_REQUEST_ERROR');
// Go back to the request form.
$this->app->enqueueMessage($message, 'error');
$this->app->redirect(Route::_('index.php?option=com_users&view=reset', false));
// Redirect to confirmation page.
$this->app->redirect(Route::_('index.php?option=com_users&view=reset&layout=confirm', false));
answered 2 days ago
SharkySharky
3,7063 silver badges11 bronze badges
3,7063 silver badges11 bronze badges
This would be a great plugin if someone could throw together in GitHub or whatnot so basic users could download/install.
– YellowWebMonkey
22 hours ago
add a comment
|
This would be a great plugin if someone could throw together in GitHub or whatnot so basic users could download/install.
– YellowWebMonkey
22 hours ago
This would be a great plugin if someone could throw together in GitHub or whatnot so basic users could download/install.
– YellowWebMonkey
22 hours ago
This would be a great plugin if someone could throw together in GitHub or whatnot so basic users could download/install.
– YellowWebMonkey
22 hours ago
add a comment
|
brett is a new contributor. Be nice, and check out our Code of Conduct.
brett is a new contributor. Be nice, and check out our Code of Conduct.
brett is a new contributor. Be nice, and check out our Code of Conduct.
brett is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Joomla Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fjoomla.stackexchange.com%2fquestions%2f26252%2fhow-to-prevent-password-reset-from-disclosing-private-email-addresses%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I love this phoenix which has risen from the ashes of an earlier difficult question. This is good content. A clear and useful question peppered with very different and insightful answers. This is the best kind of outcome. Lots of knowledge being shared here, good job everyone -- very proud of this community right now.
– mickmackusa♦
2 days ago
I'm delighted with the answers, all which I have read. I have not quite had time to dig in and apply them (disruptive life situation) but they have already served as a educational and useful point which to move forward on. One delay: I'm finally setting up Eclipse on Joomla so I can step through the code and understand the Joomla classes and MVC more clearly. I'll report back this week and also select an answer. Thank for everyone's help, forgiveness for my earlier muddled question and impatience.
– brett
23 hours ago