Programación Web: Gestión de usuarios con PHP y MySQL

1. Uso de SSL

  • Siempre que se introduzcan contraseñas en una página, es altamente recomendable el uso de SSL, que evita ataques de tipo man-in-the-middle
  • Se pueden usar certificados auto-firmados (para pruebas) o certificados firmados por una entidad gestora (Let’s Encrypt, por ejemplo, es gratuito)
  • Si se van a usar proxys, desactivarlos hasta tener SSL funcionando.

1.1. Configuración en Apache

  • Pasos para instalar un certificado SSL de Let’s Encrypt (Ubuntu 18.04, requiere poseer un dominio)
    1. sudo a2enmod ssl
    2. sudo a2enmod rewrite
    3. sudo apt-get update
    4. sudo apt-get install software-properties-common
    5. sudo add-apt-repository ppa:certbot/certbot
    6. sudo apt-get update
    7. sudo apt-get install python-certbot-apache
    8. sudo certbot --apache certonly
    9. Para renovar todos los certificados certbot renew. Para actualizar alguno en concreto, certbot --apache certonly
    10. Haz los siguientes ajustes en el virtualhost ssl (si el virtualhost http tiene añadidos, hay que incluirlos en el virtualhost ssl):
      <IfModule mod_ssl.c>
          <VirtualHost *:443>
          ServerName www.ejemplo.rs1.es
          ServerAlias ejemplo.rs1.es
          DocumentRoot /var/www/arbol
          SSLEngine On
          SSLCertificateFile /etc/letsencrypt/live/ejemplo.rs1.es/fullchain.pem
          SSLCertificateKeyFile /etc/letsencrypt/live/ejemplo.rs1.es/privkey.pem
          <FilesMatch ".(cgi/shtml/phtml/php)$">
          SSLOptions +StdEnvVars
          </FilesMatch>
          </VirtualHost>
          </IfModule>
    11. Haz los siguientes ajustes en el virtualhost http para redirigir de HTTP a HTTPS:
      RewriteEngine On
          RewriteCond %{HTTP_HOST} =ejemplo.com [OR]
          RewriteCond %{HTTP_HOST} =www.ejemplo.com
          RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [NE,R=permanent]
      • OPC:
        RewriteCond %{HTTP_HOST} =85.251.67.151
            RewriteRule ^(.*)$ https://ejemplo.com$1 [L,R=301]
    12. Comprueba si se ha habilitado la web ssl (sudo a2ensite ssl.conf)
    13. Redirige puerto 443 en el router a la IP local del servidor
    14. Reinicia apache (sudo service apache2 restart)
    15. Comprueba si hay que habilitar SSL en el panel de administración de la web, si lo tiene
      • Notas: Si hay que pasar las llaves de un servidor a otro, recuerda que el propietario es root.

1.2. Configuración en Nginx

  1. sudo apt-get install python-certbot-nginx
  2. sudo certbot --nginx certonly
  3. En el archivo de configuración de la página:
    server {
           listen 443    ssl;
           server_name   www.ejemplo.rs1.es ejemplo.rs1.es;
           root          /var/www/ejemplo;
           index         index.php index.html;
           location ~ .php$ {
             include snippets/fastcgi-php.conf;
             fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
           }
           ssl_certificate /etc/letsencrypt/live/ejemplo.rs1.es/fullchain.pem;
           ssl_certificate_key /etc/letsencrypt/live/ejemplo.rs1.es/privkey.pem;
           ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
           ssl_ciphers   HIGH:!aNULL:!MD5;
         }
  4. Para redirigir de http a https:
    • return 301 https://$server_name$request_uri;

2. Creación de la tabla con los datos de usuario

mysql -p -u bd_usuario
    > USE basedatos;
    > CREATE TABLE usuarios (user_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, username VARCHAR(100) NOT NULL, pass VARCHAR(255) NOT NULL);

3. Creación del formulario de registro / inicio de sesión

<form id="form1" method="post" action="signup.php"  onsubmit="return comprueba_regex('form1');">
        <input type="text" id="username" name="username"    placeholder="Usuario"/><br/>
        <input type="password" id="pass" name="pass"    placeholder="Contraseña"/><br/>
        <button type="submit" id="signup">Añadir usuario</button>
        </form>

4. Añadir usuarios

  • En la página a la que se envían los datos del formulario (propiedad ‘action’ del formulario)
 <?php $user = $_POST['username']; $pass = $_POST['pass']; $pass1 = hash('sha512', $pass); $sql_comprueba = "SELECT * FROM tabla WHERE username = '" . htmlspecialchars ( $user, ENT_QUOTES, 'UTF-8' ) . "'"; $result = mysqli_query($link, $sql_comprueba); $extract = mysqli_num_rows($result); if($extract != 0){     echo "<p>El nombre de usuario ya existe</p><br/>";     echo "<a href='/'>Volver</a>"; }else{     $sql = "INSERT INTO tabla     SET username = '" . htmlspecialchars ( $user, ENT_QUOTES, 'UTF-8' ) . "', pass = '$pass1'";     if(mysqli_query($link, $sql)){         echo "<p>El usuario ha sido añadido correctamente</p><br/>";     echo "<a href='/'>Volver</a>";     } else {         echo "ERROR: Could not able to execute $sql. " . mysqli_error($link);     } } mysqli_close($link); ?>
      

5. Inicio de sesión

  • En la página a la que se envían los datos del formulario (propiedad ‘action’ del formulario)
    <?php
        $user = $_POST['username2'];
        $pass = $_POST['pass2'];
        $pass1 = hash('sha512', htmlspecialchars ( $pass,   ENT_QUOTES, 'UTF-8' ));
        $sql = "SELECT * FROM tabla WHERE username = '" . htmlspecialchars ( $user, ENT_QUOTES, 'UTF-8' ) . "' AND pass = '" . $pass1 . "'";
        $result = mysqli_query($link, $sql);
        $extract = mysqli_num_rows($result);
        if($extract == 0){
        echo "<p>El usuario y/o la contraseña son incorrectos</p><br/>";
        echo "<a href='/'>Volver</a>";
        }else{
        echo "<p>Inicio correcto</p><br/>";
        echo "<a href='/'>Volver</a>";
        }
        mysqli_close($link);
        ?>

6. Creación de un registro de sesiones

  • Es una modificación del anterior código
    (...)
        $log = date('Y-m-j_H:i:s') . " - " . $_SERVER['REMOTE_ADDR'] .
        " - El inicio de sesión del usuario " . $user;
        if($extract == 0){
            $log = $log . " ha fallado";
            (...)
        }else{
            $log = $log . " ha sido un éxito";
            (...)
        }
        $log = $log . "n";
        file_put_contents('./log_'.date("j.n.Y").'.txt', $log, FILE_APPEND);
        (...)

7. Más opciones de seguridad

7.1. Fail2Ban

  • Introducción
    • Es un programa que evita los ataques por fuerza bruta, al limitar el número de intentos de inicio de sesión por IP.
  • Instalación (en Ubuntu)
    • sudo apt install fail2ban
  • Creación del filtro (ejemplo)
    • sudo vim /etc/fail2ban/filter.d/owncloud.conf
      [Definition]
          failregex={"reqId":".*","level":2,"time":".*","remoteAddr":".*","app":"core","message":"Login failed: '.*' (Remote IP: '<HOST>')"}
  • Creación del “jail” (ejemplo)
    • sudo vim /etc/fail2ban/jail.local
      [nextcloud]
          enabled = true
          filter  = nextcloud
          port    = https
          bantime  = 3000
          findtime = 600
          maxretry = 4
          logpath = /var/www/nextcloud/data/nextcloud.log
  • Reiniciar el servicio
    • sudo service fail2ban restart
  • Desbanear una IP
    • sudo fail2ban-client set nextcloud unbanip 1.2.3.4

7.2. Autentificación en dos pasos

  • La autentificación en dos pasos permite añadir una capa de seguridad a los inicios de sesión al requerir, además de la contraseña, un código de seis cifras que se envía al móvil del usuario.