Vulnerability in my system "forgot password"

0

I created a system in case the user forgets the password, but I have doubts about one thing ... HTML + PHP system

<html>
<head>
<link rel="icon" href="favicon-16.png" sizes="16x16">
<link rel="icon" href="favicon-32.png" sizes="32x32">
<meta charset="UTF-8">
<title> ::RECUPERAR SENHA:: </title>
</head>
<body>
<link href="css/forget.css" rel="stylesheet">
<script type="text/javascript" src="js/knautiluzPassMathFramework.js"></script>
<script src='https://www.google.com/recaptcha/api.js'></script>
<div id="menu"></div>
<div id="resetSenha">Insira aqui o seu e-mail:</div>
<form name="botaoy" action="" method="post">
<br>
<input type="hidden" name="password" id="password" value="none"></input>
<br>
<input type="email" required placeholder="E-mail" name="emailReset" id="emailReset" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$">
<br>
<input type="text" required placeholder="USUARIO" name="usernameReset" title="No minimo 3, no máximo 10 letras MAIÚSCULAS" id="usernameReset" pattern="[A-Z]{3,}" maxlength="10"></input>
<br>
<input type="date" required  name="birthdayReset" id="birthdayReset" min="1915-01-01" max="2006-01-01"> 
<div class="g-recaptcha" data-sitekey="6LeSEBwTAAAAAOD2kcTBvz8401DSvI5RTbtG79xK"></div>
<input onClick="knautiluzPassMathFramework();" type="submit" name="botaoy" id="gologin" value="⟳"/>
<br>
</form>
</body>
<footer></footer>
</html> 
 <?php
if(isset($_POST["botaoy"])) {

if (isset($_POST['g-recaptcha-response'])) {
    $captcha_data = $_POST['g-recaptcha-response'];
}

if (!$captcha_data) {
echo "<span id=\"captchaError\">Complete o reCAPTCHA</span>";
    return true;
}
$resposta = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=meucodigo&response=".$captcha_data."&remoteip=".$_SERVER['REMOTE_ADDR']);
if ($resposta.success) {

require ("includes/connection.php");
require ("includes/start-session.php");

$email          = mysqli_real_escape_string($mysqli, $_POST["emailReset"]); 
$username       = mysqli_real_escape_string($mysqli, $_POST["usernameReset"]);
$birthday       = mysqli_real_escape_string($mysqli, $_POST["birthdayReset"]);
$password       = mysqli_real_escape_string($mysqli, $_POST["password"]); 
$sql = $mysqli->query("SELECT * FROM data WHERE email='$email'");
$get = $sql->fetch_array();
$db_email    = $get['email'];
$db_username = $get['username'];
$db_birthday = $get['birthday'];

if ($email != $db_email || $username != $db_username || $birthday != $db_birthday) {
echo "<span id=\"msgOne\">Dados incorretos.</span>";
return true;
} else {
$sql = $mysqli->query("UPDATE data SET password = '".md5($password)."'  WHERE email =  '$email'");

$sendEmail = $mysqli->query("SELECT * FROM data WHERE email='$emailReset'");
$row = $sendEmail->num_rows;
$get = $sendEmail->fetch_array();
$assunto     = "Sua senha foi alterada!";
$emailz  = $_POST["emailReset"];
$mensagem    = 'Olá! alteramos sua senha temporariamente! Mude ela através do painel de usuário.<br>Sua nova senha é: '.$password.'';


$enviar         = "$mensagem";
require ("includes/PHPMailerAutoload.php");
define('GUSER', '[email protected]'); 
define('GPWD', 'senha@exemplo');        

function smtpmailer($para, $de, $de_nome, $assunto, $corpo) { 
    global $error;
    $mail = new PHPMailer();
    $mail->CharSet = 'UTF-8';
    $mail->IsSMTP();        
    $mail->SMTPDebug =0;        
    $mail->SMTPAuth = true;     
    $mail->SMTPSecure = 'tls';  
    $mail->Host = 'meuhost';    
    $mail->Port = 0;        
    $mail->Username = GUSER;
    $mail->Password = GPWD;
    $mail->SetFrom($de, $de_nome);
    $mail->Subject = $assunto;
    $mail->Body = $corpo;
    $mail->IsHTML(true);
    $mail->AddAddress($para);
    if(!$mail->Send()) {
        $error = 'Mail error: '.$mail->ErrorInfo; 
        return false;
    } else {
        $error = 'Mensagem enviada!';
        return true;
    }
}


 if (smtpmailer($emailz, '[email protected]', 'Knautiluz', $assunto, $enviar)) {
echo "<span id=\"msgTwo\">Senha alterada! Verifique seu e-mail com a nova senha.</span>";
 return true;

} else {
if (!empty($error)) echo $error;}}}
}
?>

My question is: the new password will be generated through a javascript when clicking the submit button and it will be stored in:

<input type="hidden" name="password" id="password"
value="none"></input>

In place of "none" will be entered a password with lowercase letters, uppercase and numbers. This password will be caught in PHP $password = mysqli_real_escape_string($mysqli, $_POST["password"]);

And then it is sent to the user's email. Basic Print System:

The user who wants to reset the password will have to enter the email username and date of birth. I still figured that a malicious user with this information could use an alert or another command to get the password generated in the password input field. It's possible? Is there a better way than the input for me to store the generated password through js?

    
asked by anonymous 11.04.2016 / 22:50

2 answers

3

The vulnerability is beyond that.

I'm not a security expert (not to say I'm no expert at all, actually!), but I'll list a few bugs that I noticed in about 3 minutes:

INPUT HIDDEN: Muitissimo High Risk)

If there is an inpu called password , you allow the user to send any password.

In other words, if you want to reset your user I simply put:

<input type="hidden" name="password" id="password" value="123456"></input>

Your date of birth can be easily obtained by social engineering, or on your Facebook, as well as the email. I have not analyzed your complete code to see if all the data is being scanned.

So your data I change to the password you want, in this case to 123456.

  

You can say: But there is Javascript, which will change value !

1 - No. Just change the names of the inputs ( name , id ), for example. Or in this case simply remove the onClick that apparently it is responsible for generating.

2 - No. Even if you create an "ultra-protected" JavaScript, you are deducing that the person is using a browser that supports it. That is, using a CURL or a WebDriver (without dynamic content) will bypass Javascript. It will even do the POST you want without any problem!

Alternative:

Generate the password via PHP, on the server side.

In an ideal scenario, allow the user to choose the password they want and continue reading this topic. =)

Send "raw" password: (High Risk)

Do not send the password by email, simple as well. If the person registered a wrong email now the "other person" has access to the account, something that could be avoided if they did not send the raw password.

In addition, if the server's network is monitored / redirected / intercepted, it will expose an attacker to the password.

Alternative:

Do not send the password via email.

False Email Confirmation: (High Risk)

If you change the password, as in method number 1, you do not need to confirm the password or change via e-mail. There is no link for the user to confirm the change or claim is (or is not) aware of the change. Therefore there is NO CONFIRMATION OF PASSWORD CHANGE!

Alternative:

1 - Send a link (no password) containing a link to "Click here to confirm your password change requested on {date} by {IP} using {BROWSE}". This email should expire in a short time (maximum 24 hours, but I believe it should become useless within 1 hour after request). The link should not contain any trace of the password!

Ideally, the link MAY ONLY BE VALIDATED BY USING THE SAME BROWSER AND / OR IP! That is, if the user used Chrome in 1.2.3.4, only 1.2.3.4 can accept the change. So if someone has access to the link improperly they will not be able to change the password, because they are not using the same computer as the one they requested.

2 - Send an SMS (this is paid for) or use the F2A so that the user has to confirm the change also using this feature. That way, if the email is hacked you will not be able to confirm the access. In addition to confirming the email (stated in the item above) you will have to confirm the F2A.

Account Lockout: (Low)

On your current system, if I want to "troll" you, I can be asking for a password reset every time, so you never know what the password is. This is because your system overwrites the old password immediately, this prevents you from logging in with your old password.

Assuming there is a password reset spam, your password would be modified at all times, which in the end would block / block access to your account, because you can not know what your current password is. >

As the password changes immediately, without any confirmation, you end up creating a major problem.

Alternative:

Create a table of changed and not "approved" passwords via e-mail, SMS or F2A. This way the user will still have access with the old password.

Ideally, if the user requests the reset, then entering the old password automatically overrides the change, since the user has access to the old password. This would not be possible in your code.

In short: this way the user will still have access using the old password until he accepts the reset.

Also block if there are too many requests for a specific user reset per IP zone.

    
11.04.2016 / 23:57
0

I would advise you to use only the request for email and user in the form. When the user submits the form the system checks that user and email in the database to create a base64_encode of the email and user and still create a new field in the table to store a microtime () and send as token to the e -mail user with a link to change password.

The person who will access the email will have to click on this link to confirm that the data is his own and then will be redirected back to his site to another form in which he will provide the new password. Then you will change the password from the microtime (), email and user data and then delete the microtime () from the field so that this action can be performed only once.

    
12.04.2016 / 19:06