Diferencia entre revisiones de «PHP Validando usuarios»

De MediaWiki
Ir a la navegación Ir a la búsqueda
Línea 79: Línea 79:
 
<br />
 
<br />
 
: '''Arquivo UD4_Exemplo1_Validacion_Formulario.php'''
 
: '''Arquivo UD4_Exemplo1_Validacion_Formulario.php'''
−
::<syntaxhighlight lang="java" enclose="div" highlight="2,3,45" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="2,3,47" >
 
<?php
 
<?php
 
     session_start();
 
     session_start();
 
     unset($_SESSION['autenticado']);
 
     unset($_SESSION['autenticado']);
 +
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); // Para evitar ataques csrf
 
?>
 
?>
  
Línea 109: Línea 110:
 
     <body>
 
     <body>
 
         <form id="frmValidacion" class="formularios" method="post" action="procesar_UD4_Exemplo1_Validacion_Usuarios.php">
 
         <form id="frmValidacion" class="formularios" method="post" action="procesar_UD4_Exemplo1_Validacion_Usuarios.php">
 +
            <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
 
             <div>     
 
             <div>     
 
                 <div class='etiqueta'>Login:</div>
 
                 <div class='etiqueta'>Login:</div>
Línea 128: Línea 130:
 
     </body>     
 
     </body>     
 
</html>
 
</html>
 +
  
 
</syntaxhighlight>
 
</syntaxhighlight>
Línea 133: Línea 136:
 
: Liña 2: '''Sempre debemos ter o session_start() ao comezo da páxina''' se imos traballar con variables de sesión.
 
: Liña 2: '''Sempre debemos ter o session_start() ao comezo da páxina''' se imos traballar con variables de sesión.
 
: Liña 3: Dita variable de sesión estará explicada posteriormente. Adiantar que é a variable que imos utilizar para deixar visualizar ao usuario as páxinas protexidas (que requiran unha autenticación previa).
 
: Liña 3: Dita variable de sesión estará explicada posteriormente. Adiantar que é a variable que imos utilizar para deixar visualizar ao usuario as páxinas protexidas (que requiran unha autenticación previa).
−
: Liña 45: Facemos o include das mensaxes de erro e aviso se se producen na páxina de procesar.
+
: Liña 47: Facemos o include das mensaxes de erro e aviso se se producen na páxina de procesar.
 
<br />
 
<br />
 
: Visualizamos isto:
 
: Visualizamos isto:
Línea 149: Línea 152:
 
<br />
 
<br />
 
: ''' Arquivo procesar_UD4_Exemplo1_Validacion_Usuarios.php'''
 
: ''' Arquivo procesar_UD4_Exemplo1_Validacion_Usuarios.php'''
−
::<syntaxhighlight lang="java" enclose="div" highlight="9,12,26" >
+
::<syntaxhighlight lang="java" enclose="div" highlight="8,13,28" >
 
<?php
 
<?php
 
/* Lembrar quitar isto ao probar o scripts sen erros */
 
/* Lembrar quitar isto ao probar o scripts sen erros */
Línea 156: Línea 159:
 
error_reporting(E_ALL);
 
error_reporting(E_ALL);
  
−
if (!isset($_POST['btnRexistrar'])){    // Se non vimos de premer o botón de rexistro volvemos a login
+
 
 +
session_start();
 +
 
 +
if (!isset($_POST['btnRexistrar']) || ($_POST['csrf_token'] !== $_SESSION['csrf_token'])){    // Se non vimos de premer o botón de rexistro volvemos a login. O csrf_token para evitar ataques
 +
    unset($_SESSION['csrf_token']);
 
     header("location:UD4_Exemplo1_Validacion_Formulario.php");
 
     header("location:UD4_Exemplo1_Validacion_Formulario.php");
 
     exit();
 
     exit();
 
}
 
}
−
 
−
session_start();
 
  
 
require ('/var/www/confBD/bd.inc.php');
 
require ('/var/www/confBD/bd.inc.php');
Línea 197: Línea 202:
 
     }
 
     }
 
}
 
}
 +
 +
unset($_SESSION['csrf_token']); // Para evitar ataques csrf
  
 
$url = sprintf("UD4_Exemplo1_Validacion_Formulario.php");
 
$url = sprintf("UD4_Exemplo1_Validacion_Formulario.php");
Línea 202: Línea 209:
  
 
?>       
 
?>       
−
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
  
−
: Liña 12: '''Sempre debemos ter o session_start() ao comezo da páxina''' se imos traballar con variables de sesión.
+
: Liña 8: Fixarse que despois da orde 'header' hai un exit para que o script non continúe executándose. Isto é así xa que o header non se enviará ao cliente ata que non remate o script. Dependerá de nos como programadores se queremos 'facer' algo máis antes de redirixir a páxina do navegador do cliente.
−
<u>Nota:</u> Fixarse que despois da orde 'header' hai un exit para que o script non continúe executándose. Isto é así xa que o header non se enviará ao cliente ata que non remate o script. Dependerá de nos como programadores se queremos 'facer' algo máis antes de redirixir a páxina do navegador do cliente.
+
: Liña 13: '''Sempre debemos ter o session_start() ao comezo da páxina''' se imos traballar con variables de sesión.
 +
: Liña 28: Encriptamos o password.
  
  
Línea 214: Línea 221:
  
  
 +
<br />
  
−
<br />
 
 
===Validando usuarios===
 
===Validando usuarios===
  

Revisión del 08:54 20 nov 2023

Introdución

  • Un aspecto ao que case sempre imos enfrontarnos é ao de permitir o acceso a certas páxinas en función dos permisos que teña un determinado cliente.
  • Para obter ditos permisos teremos que validar ao usuario e identificalo.
A identificación case sempre vai vir dun formulario no que o usuario introduce o seu login-password.
Nos recollemos ditos datos e normalmente faremos unha consulta a unha base de datos para comprobar que o usuario existe.
  • Neste punto imos ver como podemos facer para que o usuario non poida entrar nas páxinas se non está validado.
Como aínda non sabemos 'conectar' con bases de datos imos supoñer que o usuario ten que ter de nome 'pepe' e de password '12345'. En caso doutra combinación supoñemos que o usuario non está autorizado para acceder ao sitio web.
Fixarse que estamos implementando un mecanismo de autenticación de usuarios.
Non indicamos nada acerca dos permisos que ten dito usuario. Por exemplo, un administrador e un usuario son usuarios que teñen dereito de conexión ao sitio web, pero cada un deles terá permisos diferentes para poder realizar accións distintas...



  • IMPORTANTE: Durante o proceso de autenticación, o navegador envía ao servidor o usuario/password introducido polo usuario. Eses datos deben ir cifrados para que non poidan ser obtidos de forma fraudulenta pola rede. Para iso é necesario empregar certificados dixitais que no caso das páxinas web, tradúcese en empregar unha conexión https no que o servidor web emite un certificado dixital váliado que o indentifica.
Nunca se debe desenvolver unha aplicación web no que non se empregue este tipo de certificado.
Como facelo queda fora dos contidos deste curso, polo que as probas que estades a desenvolver empregan conexións non seguras de tipo http.

Exemplo rexistro/validación de usuario e carrito da compra

  • Imos facer un pequeno sitio web no que imos poder rexistar novos usuarios e despois mediante unha validación imos poder ter acceso as páxinas para mercar produtos e xestionar un carrito da compra




Rexistro de usuarios

  • Nesta páxina vaise amosar un login/password e vaise rexistrar un usuario/password.
Primeiro temos que crear a táboa usuarios no Mysql:
1 CREATE TABLE `php`.`usuarios` (
2   `id` INT NOT NULL AUTO_INCREMENT,
3   `login` VARCHAR(50) NOT NULL,
4   `password` VARCHAR(255) NOT NULL,
5   PRIMARY KEY (`id`),
6   UNIQUE INDEX `login_UNIQUE` (`login` ASC) VISIBLE);
Nesta táboa o password vai estar encriptado cunha función de hash que en principio devolve como mínimo 60 caracteres, pero que pode chegar a devolver ata 255 caracteres, por se nun futuro cambia a implementación.



  • Agora necesitamos gardar usuarios/password nesa táboa. Para iso imos facer uso das funcións:
  • Engadimos ao arquivo bd.inc.php que queda fora da ruta onde apunta o sitio web, a orde para engadir un usuario. Lembrar que isto xa o vimos na UD3.
Podemos empregar un procedemento almacenado de Mysql ou a orde SQL Insert. Lembrar que xa expliquei que é moito máis seguro empregar o procedemento ou ordes prepare.

Arquivo /var/www/confBD/bd.inc.php

1 define('INSERIR_USUARIOS',"INSERT INTO usuarios (login,password) VALUES ('%s','%s')");


  • Creamos unha páxina php para dar de alta usuarios.
Como queremos enviar a esta páxina información se o rexistro foi correcto ou se houbo algún tipo de erro, imos crear un include no que se amosarán o contido de dúas variables de sesión que imos empregar para isto:

Arquivo UD4_Exemplo1_Mensaxes.inc.php

        <?php
            if (!empty($_SESSION['msg'])){
                printf("<div>INFORMACIÓN: <b>%s</b>",$_SESSION['msg']);
            }
            if (!empty($_SESSION['error'])){
                printf("<div>ERROR: <b>%s</b>",$_SESSION['error']);
            }
            unset($_SESSION['msg']);
            unset($_SESSION['error']);




Arquivo UD4_Exemplo1_Validacion_Formulario.php
<?php
    session_start();
    unset($_SESSION['autenticado']);
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); // Para evitar ataques csrf
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
    <head>
        <meta charset="utf-8" />
        <title>Formulario</title>
        <style>
            .formularios{
                width: 30%;
                margin: 0px auto;
            }
            .etiqueta{
                float: left;
                width: 190px;
            }
            .botonesformularios{
                width: 50%;
                margin: 30px auto;
                text-align: center;
            }
        </style>
    </head>
    <body>
        <form id="frmValidacion" class="formularios" method="post" action="procesar_UD4_Exemplo1_Validacion_Usuarios.php">
            <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
            <div>    
                <div class='etiqueta'>Login:</div>
                <input type="text" required size="15" maxlength="15" name="txtLogin" />
            </div>                
            <div>
                <div class='etiqueta'>Password:</div>
                <input type="password" required size="15" maxlength="15" name="txtPassword" />
            </div>                
            <div class="botonesformularios">
                <input type='submit' value="ENVIAR"  name="btnRexistrar" />
                <input type='reset' value="LIMPAR" name="btnLimpar" />
            </div>
        </form>

        <?php 
        include('UD4_Exemplo1_Mensaxes.inc.php')
        ?>
    </body>    
</html>
Liña 2: Sempre debemos ter o session_start() ao comezo da páxina se imos traballar con variables de sesión.
Liña 3: Dita variable de sesión estará explicada posteriormente. Adiantar que é a variable que imos utilizar para deixar visualizar ao usuario as páxinas protexidas (que requiran unha autenticación previa).
Liña 47: Facemos o include das mensaxes de erro e aviso se se producen na páxina de procesar.


Visualizamos isto:

Php validacion 1.jpg




  • O seguinte será rexistrar o usuario/password na táboa usuarios.
Para iso imos facer uso da función password_hash() que permite encriptar un texto cun cifrado e vai ser a password a gardar na táboa de usuarios.
Para comprobar o usuario cando intente entrar empregaremos password_verify().



Arquivo procesar_UD4_Exemplo1_Validacion_Usuarios.php
<?php
/* Lembrar quitar isto ao probar o scripts sen erros */
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);


session_start();

if (!isset($_POST['btnRexistrar']) || ($_POST['csrf_token'] !== $_SESSION['csrf_token'])){    // Se non vimos de premer o botón de rexistro volvemos a login. O csrf_token para evitar ataques
    unset($_SESSION['csrf_token']);
    header("location:UD4_Exemplo1_Validacion_Formulario.php");
    exit();
}

require ('/var/www/confBD/bd.inc.php');

try {
    $conex = new mysqli(SERVIDOR, USUARIO, PASSWORD,BD);   
    $conex->set_charset('utf8mb4');
    // Xestionamos a operacion do segundo formulario => Alta , Baixa ou Modificacion
    if ((strlen($_POST['txtLogin'])<4) || (strlen($_POST['txtPassword'])<4)){
        $_SESSION['error'] = sprintf("A lonxitude do login e password non poden ter menos de 4 caracteres...");
    }
    else {
        // Eliminamos caracteres non permitidos
        $login = filter_var($_POST['txtLogin'],FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES);
        $password = password_hash($_POST['txtPassword'],PASSWORD_DEFAULT);

        // Escapamos as comillas simples e dobres
        $login = $conex->real_escape_string(strtoupper($login));
        $ordeSQL=sprintf(INSERIR_USUARIOS,$login,$password);
        $conex->query($ordeSQL);

        $_SESSION['msg'] = sprintf("Usuario rexistrado correctamente.");        
    }  
        
}   // Pecha o try da parte superior da páxina. Lembrar que aos usuarios non se lle deben amosar os erros. Isto está posto a nivel informativo para os programadores
catch (mysqli_sql_exception $e) {
    $_SESSION['error']=sprintf("Erro mysql: %s",htmlentities($e->getMessage()));    // Lembra que getMessage non se debe enviar ao cliente. Posto por motivos de depuración
}   
catch (Expcetion $e) {
    $_SESSION['error']=sprintf("Erro xeral: %s",htmlentities($e->getMessage()));    // Lembra que getMessage non se debe enviar ao cliente. Posto por motivos de depuración
}
finally{
    if(!empty($conex)){
        $conex->close();
    }
}

unset($_SESSION['csrf_token']); // Para evitar ataques csrf

$url = sprintf("UD4_Exemplo1_Validacion_Formulario.php");
header("Location:" . $url);

?>


Liña 8: Fixarse que despois da orde 'header' hai un exit para que o script non continúe executándose. Isto é así xa que o header non se enviará ao cliente ata que non remate o script. Dependerá de nos como programadores se queremos 'facer' algo máis antes de redirixir a páxina do navegador do cliente.
Liña 13: Sempre debemos ter o session_start() ao comezo da páxina se imos traballar con variables de sesión.
Liña 28: Encriptamos o password.





Validando usuarios

Liñas 15-18: En caso de coincidir o login/password (nunha situación real teríamos que facer unha consulta a unha base de datos) utilizamos unha variable de sesión de nome autenticado e damos un valor de 1. En caso contrario terá un valor de 0.
Dita variable debemos usala en todas as páxinas onde sexa necesario que o usuario estea autenticado. Vexamos un exemplo na seguinte páxina.


Nome da páxina: UD4_Exemplo1_Validado.php
 1 <?php
 2   session_start();
 3   
 4   if ($_SESSION['autenticado']!=1) {  // Mellor preguntar polo valor que permito o acceso.
 5         header('location:UD4_Exemplo1_Validacion_Formulario.php');
 6         exit();
 7   }
 8 
 9 ?>
10 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
11     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
12 <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
13     <head>
14         <title>Usuario autenticado</title>
15     </head>
16     <body>
17         <h1>Se podes ver isto es un usario autenticado...</h1>
18         
19         <a href="UD4_Exemplo1_Validacion_Formulario.php">Pulsa para volver a validarte...</a>
20     </body>
21 </html>
Liña 2: Sempre debemos ter o session_start() ao comezo da páxina se imos traballar con variables de sesión.
Liñas 4-7: É onde facemos a validación do usuario. Se dito usuario non foi autenticado, entón irá a páxina inicial.






-- Ángel D. Fernández González -- (2023).