En una ocasión estaba leyendo sobre los ataques de temporización y la recomendación de usar hash_equals en lugar de simples comparaciones con PHP. Más tarde me puse a investigar y supe la razón de usar hash_equals cuando estamos tratando con contraseñas (que al final son cadenas).
Esto es independiente del lenguaje, o eso creo. No daré una definición formal sino una que espero todos puedan entender.
Un ataque de temporización es aquel en donde un atacante logra, a través de suposiciones y acercamientos, adivinar una contraseña.
Veamos cómo funciona… para esto, definamos que nuestra contraseña será “AAA123”.
Como seres humanos, si nos dieran a comparar una cadena, compararíamos carácter por carácter. No lo hacemos siempre, pero si fuera una cadena larga y sin sentido sí lo haríamos.
Por ejemplo, “Hola” y “Hla”… comparamos carácter por carácter, primero la H y la H. Luego la o y la l, y justo ahí decimos que no son iguales. ¿gastamos tiempo comparando las demás letras? no, porque ya desde la o nos dimos cuenta de que no son iguales.
Los lenguajes de programación (o al menos PHP) también son como nosotros: comparan y la primera vez que encuentran algo distinto regresan, no siguen comparando.
Esto se hace siempre cuando usamos ===
o incluso strcmp
.
Las contraseñas son cadenas, simples cadenas. Ya sea hasheadas o no, son cadenas al final de todo. Imaginemos que están en texto plano, y que por cada comparación de un carácter se utiliza 1 segundo sólo para efectos de simplicidad.
El lenguaje comparará carácter por carácter, primero la A y luego el 1. No coinciden así que desde ahí regresa falso. ¿cuánto tiempo tardó? exacto, 1 segundo.
Ahora el atacante ve que esa contraseña no es correcta e intenta con otra…
PHP va y compara la A con la A, muy bien, eso sí coincide. Ahora con A y S, eso no coincide. ¿cuánto tiempo tardó? 2 segundos.
Entonces aquí el atacante se da cuenta de algo… aunque no ponga la contraseña correcta, a veces tarda más y a veces menos. Analizando más a fondo se da cuenta de que si pone el inicio correcto, tardará más. Hasta ahora sabe que la contraseña comienza con A. Entonces prueba de nuevo:
En este caso las primeras 3 letras coinciden, y al comparar 1 con A ya no pasa, pero tarda 4 segundos. Así que eso significa que las 3 primeras están bien. Prueba de nuevo:
Ya casi lo logra, ahora tardará 5 segundos (porque los primeros 4 son correctos pero con el quinto se detiene, al comparar 1 y 2). Y bueno, para no hacerlo largo, al final el atacante podrá adivinar la contraseña porque el sistema le irá indicando cómo va todo.
Es como jugar a frío y caliente. Le vas preguntando al sistema si la contraseña empieza con determinada letra, y él te dice si sí o no según el tiempo que se tarde. Nunca he visto un ataque de estos, porque las computadoras de hoy son rápidas pero supongo que sí se puede medir.
En resumen, entre más correcta sea la contraseña, más tiempo tardará en responder.
La función hash_equals nos asegura tardar el mismo tiempo cuando compare cadenas, sin importar si desde el inicio no coinciden. Pero cuidado, que si las cadenas no miden lo mismo se regresará false inmediatamente.
Utiliza hash_equals
, pásale como primer argumento la contraseña que tienes guardada en la base de datos (o la contraseña en la que confíes) y como segundo argumento la contraseña que el usuario proporciona (no lo hagas al revés)
Esta función regresa un booleano indicando si coinciden o no.
Te recomiendo que uses eso si comparas contraseñas con tu propio cifrado; porque si quieres un método confiable que se implementa sin esfuerzo puedes usar password_hash y password_verify.
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