Es una buena práctica (y algo que debemos hacer todos) cifrar las contraseñas si las vamos a guardar en una base de datos. También es importante hacerlo con un algoritmo de un solo camino; es decir, que se pueda cifrar pero que nunca se pueda hacer el proceso inverso.
Recordemos que la seguridad absoluta no existe y que siempre estamos propensos a un ataque de cualquier tipo, así que hay que proteger cada cosa individualmente.
Supongamos que nuestro servidor FTP sí está bien protegido, y que ningún usuario malicioso puede acceder a él. Ahora imaginemos que alguien logra hacer un ataque a la base de datos, y consigue todos los nombres de usuario y contraseñas. Lo que conseguirá serán contraseñas cifradas que no le servirán para nada. Pero si no las ciframos, podrán hacer lo que se les antoje.
PHP ya viene con una opción para cifrar las contraseñas. No debemos usar nunca SHA1 ni MD5, porque aunque no son reversibles sí son predecibles con ataques de diccionario.
Aquí pongo un ejemplo:
Si yo uso SHA1 para cifrar “123” obtendré “40bd001563085fc35165329ea1ff5c5ecbdbbeef“. Esto nunca cambiará; siempre que yo cifre “123” obtendré el mismo resultado. Si alguien obtiene la contraseña cifrada que será “40bd001563085fc35165329ea1ff5c5ecbdbbeef”, no sabrá cuál contraseña plana es.
Pero comenzará a probar diferentes contraseñas y las irá cifrando, una por una. Puede comenzar con las más comunes, como 12345, 0000, etcétera. Por lo que conseguirá los siguientes resultados:
E irá probando hasta que llegue a 123. Se verá así:
Lo peor de esto es que ya hay diccionarios online que tienen la mayoría de contraseñas más comunes y no tan comunes. Por eso nunca se debe usar esta función.
Con MD5 es lo mismo, así que no lo explicaré
Cuando usamos la función que PHP recomienda, se le añade sal a la contraseña cifrada. Es una cadena aleatoria que siempre producirá resultados diferentes.
La primera vez que cifre 123 puede que el resultado sea $2y$10$I4tJZFA.mxRSaxiy/uLUWOAB8CCoBI5UJUJZ/pkJ278oYJm6nstJ. La segunda $2y$10$uxHsXhUq90CzCbPNeoCL/enuYtJVmChl2Bc9biUJnq/LYtDDusk5K, la tercera $2y$10$8lVMtOjKf6nsorwQp4cWW.hzfuVqk.MyuKzesEPZu2r7fKt0X2V4K y así sucesivamente. Por lo que siempre dará un resultado distinto, y nunca se le podrá hacer un ataque como el que menciono arriba.
Así que para guardar estas contraseñas el algoritmo es:
Y para comprobar si esta contraseña es correcta cuando el usuario intente acceder es:
El manual oficial recomienda que si vamos a usar password_hash declaremos nuestro campo en la base de datos con una longitud de 255.
Voy a abstraer y omitir la conexión a la base de datos porque explicarlo no es el propósito de este post. Así que supondré que el usuario sabe manejar bases de datos y sus conexiones.
if(isset($_POST["nombre_usuario"]) && isset($_POST["password"])){ $usuario = $_POST["nombre_usuario"]; $pass = $_POST["password"]; $passCifrada = password_hash($pass, PASSWORD_DEFAULT); $baseDeDatos->prepare("INSERT INTO usuarios (nombre, pass) VALUES (?,?);"); $baseDeDatos->execute([$usuario, $passCifrada]); }
En el código de arriba tomamos el usuario y la contraseña del usuario, que pudieron ser enviadas por un formulario. Preparamos la consulta SQL para evitar inyecciones y guardamos.
Es importante notar que usamos password_hash() y le pasamos como primer argumento la contraseña plana, y como segundo una constante que es el algoritmo a ser utilizado. Recomiendo usar siempre esta constante.
Ese fue el proceso para guardar el usuario y la contraseña.
Ahora imaginemos que el usuario intenta acceder, y que igualmente manda el nombre de usuario y la contraseña por un formulario. El código quedaría así:
if(isset($_POST["nombre_usuario"]) && isset($_POST["password"])){ $nombreUsuario = $_POST["nombre_usuario"]; $pass = $_POST["password"]; $baseDeDatos->prepare("SELECT pass FROM usuarios WHERE nombre = ? LIMIT 1;"); $baseDeDatos->execute([$nombreUsuario]); $passObtenida = $baseDeDatos->fetch()->pass; //Aquí comprobamos: if(password_verify($pass, $passObtenida) === TRUE){ //Datos correctos }else{ //Datos incorrectos } }
Así es como, a grosso modo, podemos comprobar si las credenciales de determinado usuario son válidas, al mismo tiempo que protegemos su contraseña.
Es muy importante mencionar que no debemos intentar crear nuestros propios algoritmos, por más que pensemos que somos listos nunca debemos de intentar hacerlo por nuestra cuenta.
Hoy te voy a presentar un creador de credenciales que acabo de programar y que…
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Esta web usa cookies.
Ver comentarios