Autor Tema: Creacion de un formulario de cambio de contraseña con link de activación  (Leído 440 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Conectado Kimeraweb

  • AdminSite
  • *
  • Topic Author
  • Mensajes: 2127
  • de
  • Agradecimientos: 745
  • Kimeraweb
    • http://l2devsadmins.net
  • Cronica: : Alfa
  • Revision: Alfa
  • S.O: Windows 10
  • Serverpack : Desarrollo interno
A Reynald0, Fissban y marko, les gusta este post.

gracias
Este post tiene 3 agradecimientos
  • Añade a tus favoritos
    Este caso es parecido a CAMBIO DE CONTRASEÑA DE UNA CUENTA. La diferencia es que ahora el usuario recibe en su e-mail un enlace de activación.

    Para hacerlo seguro, en enlace contiene todos los datos encriptados que se envian desde el formulario.

    Cuando el usuario recibe el e-mail, el enlace del e-mail le lleva a otra página que desencripta el enlace recibido y ejecuta el query para activa la nueva contraseña.

    Esta sería la página del formulario:

    Código: [Seleccionar]
    <?php
    // Evitar el intento de flooding, solo una petición de cambio de pass cada 5 segundos.
    if (!isset($_SESSION))
    {
        session_start();
    define("NO_HACK",true); // Solo se define la constante si es la primera vez que entra al formulario.
    } else {
    $_SESSION['last_session_request'] = time(); // Solo crearemos la sesión si no ha sido creada.
    }

    // Si existe una sesión, se comprueba que tiene al menos 5 segundos de antigüedad.
    // Si no tiene al menos 5 segundos, debe tratarse de un ataque. Nadie escribe tan rápido ;p
    if($_SESSION['last_session_request'] > time() - 5)
    {
    // Opcional, pon aqui tu script para hacer un log del intento de flooding, ejemplo, mandarte un email o guardar la IP del visitante en la base de datos.
    header("location: /soloUnaPeticionCadaPocosSegundos.html");
    exit;
    }

    ?>
    <!doctype html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Documento sin título</title>
    </head>
    <?php
    // Este script solo se ejecuta si llega un $_POST['CambioPass']
    if (@$_POST['CambioPass'])
    {
    // Si usan scripting, se saltan la proteccion del flooding, por lo que miraremos si existe la constante global NO_HACK antes de seguir.
    if (!defined(NO_HACK))
    {
    header("location: /intentoDeHack.html");
    }

    // Antes de introducir los datos del formulario en el query, comprobar que no contienen signos especiales para crear inyección.
    $caracteres_prohibidos = array ("<", ">", "-", "javascript", "'", "\"");
    $login = str_replace($caracteres_prohibidos,"",$_POST['login']); // Cambiamos el caracter prohibido por nada.
    $email = str_replace($caracteres_prohibidos,"",$_POST['email']);
    $pass = base64_encode(pack("H*", sha1(utf8_encode($_POST['passw'])))); // Aqui no hace falta comprobarlo, ya que al encriptar la password, creará una nueva cadena.
    $nuevaPass = base64_encode(pack("H*", sha1(utf8_encode($_POST['nuevaPass']))));
    // Importante si no queremos que sea tratado como spam y el servidor de correos nos mande el email a la carpeta de SPAM.
    // Esto solo funciona si tenemos un dominio creado. Si no poseemos un dominio, irá igualmente a la carpeta de SPAM.
    $cabecera_email = 'From: miserver@midominio.com' . "\r\n" .'Reply-To: webmaster@midominio.com' . "\r\n" . 'X-Mailer: PHP/' . phpversion();

    // Conexion a la base de datos
    // $conexion = mysqli_connect($ip_server,$usuario,$pass,$nombre_base_datos);
    $conexion = mysqli_connect("127.0.0.1","root","","l2j_h5_ls_bitbucket");
    $query = mysqli_query($conexion, "SELECT * FROM accounts WHERE login='".$login."' AND password='".$pass."' AND email='".$email."'"); // SELECCIONA (* todo) DESDE accounts DONDE login=$login... (las 3 coincidencias)

    $numero_de_filas_seleccionadas = mysqli_num_rows($query); // Contamos las coincidencias obtenidas
    if ($numero_de_filas_seleccionadas == 1) // Solo puede haber 1!
    {
    // Si hay una coincidencia, todos los datos son correctos.

    // Encriptamos todos los datos del formulario para enviar por e-mail y activar por link
    $options = $login."*".$mail."*".$pass."*".$nuevaPass;
    $clave_encriptacion = "n0_m3_3sp13s_K_t_v30_ll3g4r_l0b@"; // cambiala por otro o lo sabra todo el mundo!

    // Enviaremos el resto de los datos del usuario encriptados para hacer el query en la pagina-> activarpass.php
    $options_encripted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($clave_encriptacion), $options, MCRYPT_MODE_CBC, md5(md5($clave_encriptacion))));

    // El link que clicará el usuario
    $link = "http://myserver.com/activarpass.php?&nuevapass=".$options_encripted;
    // El usuario obtendrá algo como: http://myserver.com/activarpass.php?nuevapass=af029432409fdfm3b3849A987686546gfv8zxcv9xzv78

    // La mandamos por correo
    mail($mail,"L2Server - Link de activacion de su contraseña", "Ha solicitado actualizar su contraseña, para ello, haga click en el enlace: <br><br>".$link,$cabecera_email);

    // Le avisamos que vea su bandeja de entrada
    header("location: /tienes_un_email_de_activacion.html");
    }
    // Si no hay una coincidencia
    else if ($numero_de_filas_seleccionadas == 0) // No hubo coincidencias!
    {
    header("location: /ErrorEnLoginPassEmail.html"); // Mostramos que ha introducido mal cualquiera de estos datos
    }
    // Si hay más de 1 coincidencia
    else if ($numero_de_filas_seleccionadas >1)
    {
    // Un email al administrador, se encontraron mas de 1 coincidencia!!
    mail("admin@myserver.com","Error cambiando pass","El usuario ".$login." con IP: ".$_SERVER['REMOTE_ADDR']." ha intentado cambiar su contraseña y ha producido más de una coincidencia.",$cabecera_email);
    // Un mensaje para el usuario
    header("location: /AvisoErrorAdminAvisado.html");
    }
    }
    ?>
    <body>
    <form id="CambioPass" name="form1" method="post" action="index.php">
      <table width="36%" border="0" align="center">
        <tbody>
          <tr>
            <td width="50%" align="center">Login</td>
            <td width="50%" align="center"><input type="text" name="login" id="login"></td>
          </tr>
          <tr>
            <td align="center">Password</td>
            <td align="center"><input type="password" name="passw" id="passw"></td>
          </tr>
          <tr>
            <td align="center">E-Mail</td>
            <td align="center"><input type="text" name="email" id="email"></td>
          </tr>
          <tr>
          <td align="center">Nueva Password</td>
          <td align="center"><input type="password" name="nuevaPass" id="nuevaPass"></td>
          </tr>
          <tr>
            <td colspan="2" align="center"><p>&nbsp;
              </p>
              <p>
                <input type="submit" name="submit" id="submit" value="Enviar">
            </p></td>
          </tr>
        </tbody>
      </table>
    </form>
    </body>
    </html>

    y esta es la página donde el usuario hace click desde su correo electrónico:

    Código: [Seleccionar]
    <?php
    // Evitar el intento de flooding, solo una petición de cambio de pass cada 5 segundos.
    if (!isset($_SESSION))
    {
        session_start();
    } else {
    $_SESSION['last_session_request'] = time(); // Solo crearemos la sesión si no ha sido creada.
    }

    // Si existe una sesión, se comprueba que tiene al menos 5 segundos de antigüedad.
    // Si no tiene al menos 5 segundos, debe tratarse de scripting, ya que esta página es accesible desde cualquier parte de internet.
    if($_SESSION['last_session_request'] > time() - 5)
    {
    // Opcional, pon aqui tu script para hacer un log del intento de flooding, ejemplo, mandarte un email o guardar la IP del visitante en la base de datos.
    header("location: /soloUnaPeticionCadaPocosSegundos.html");
    exit;
    }

    // Han clicado el enlace y nos mandan la nueva password
    if ($_GET['nuevapass'])
    {
    // Inicializando la variable de encriptacion
    $clave_encriptacion = "n0_m3_3sp13s_K_t_v30_ll3g4r_l0b@";
    // Obtener los datos del formulario
    $options_encrypted = $_GET['options'];
    // Desencriptamos el enlace que trae todos los elementos del formulario
    $options = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($clave_encriptacion), base64_decode($options_encrypted), MCRYPT_MODE_CBC, md5(md5($clave_encriptacion))), "\0");
    // En estos momentos, options debe ser una cadena con 3 asteriscos -> miLoginUser*miEmail*miPasswordActual*miNuevaPassword

    // Verifiquemos si es verdad o es un intento de scripting
    // Partimos la cadena de texto en asteriscos
    $options_array = explode("*",$options);
    // Si al partir la cadena de texto no obtenemos un array de 4 elementos, es que han intentado ejecutar un script para crear una cuenta desde fuera de la web.
    if (sizeof($options_array)=!4)
    header ("Location: /intento_de_scripting.html");

    // Si hemos llegado hasta aqui, todo va bien. Todas las entradas ya han sido comprobadas.
    // Según estadísticas, cada 6 meses es una practica segura cambiar la clave de encriptacion en esta página y en la página del formulario.
    // Para ser totalmentes seguros, que contenga numeros, letras y caracteres. Al menos una longitud de 8. Da una probabilidad entre 4^20 de ser hackeados (40 trillones entre una).

    // Conexion a la base de datos
    // $conexion = mysqli_connect($ip_server,$usuario,$pass,$nombre_base_datos);
    $conexion = mysqli_connect("127.0.0.1","root","","l2j_h5_ls_bitbucket");
    $login = $options_array[0];
    $email = $options_array[1];
    $pass = $options_array[2];
    $nuevaPass = $options_array[3];

    // Ejecucion del query
    // Ya que las entradas fueron verificadas en el formulario, no es necesario volverlo a hacer.
    $query = mysqli_query($conexion, "UPDATE accounts SET password='".$nuevaPass."' WHERE login='".$login."' AND password='".$pass."' AND email='".$email."'");
    if (mysqli_fetch_array($conexion)==1) // Contamos el número de filas afectadas por el query (debe ser 1, ya que el SELECT dio 1)
    {
    // Enviamos un email al propietario de la cuenta
    mail($email,"Cambio de contraseña en su cuenta de L2","La contraseña de su cuenta ".$login." ha sido cambiada. Recuerde que este servidor guarda sus datos encriptados, por lo que no podemos facilitarle sus datos originales.<br><br> Saludos del equipo de administracion.", $cabecera_email);

    header("location: /cambioDePassExitosa.html");
    }
    }
    ?>
    « Última modificación: Septiembre 03, 2017, 04:23:34 am por Kimeraweb »
    "Sólo existen dos días al año en los que no se puede hacer nada: ayer y mañana" (Dalai Lama)