Configurar
Un sistema LAMP (Linux, Apache, MySQL, PHP). El acceso a db se realiza a través de la interfaz de bucle invertido (tal vez no en el futuro, dependiendo de la solución de alojamiento).
La base de datos contiene una tabla con el nombre de usuario, el hash de la contraseña, la contraseña de hash (y algunos otros datos irrelevantes para esta discusión). El usuario de la base de datos para la aplicación solo tiene el permiso de ejecución, lo que limita el acceso solo a los procedimientos almacenados.
Solución común
Aplicaciones PHP:
- Lee salt y hashedPW usando "
select * from table where user=?
" - El usuario de hash ingresó la contraseña con salt y hace una comparación de cadenas en la aplicación para hashedPW de DB (sé que password_hash y password_verify ahora son mejores, pero ¿es mejor mi manera todavía?)
- Si las cadenas coinciden, el usuario se autentica.
Mi solución
La base de datos tiene algunos procedimientos almacenados (SP) relevantes para esta discusión:
-
check_user(user, HTTP_USER_AGENT, REMOTE_ADDR)
SP devuelve unview
de la tabla de usuarios que solo devuelve la sal si el nombre de usuario se encuentra en la consulta. -
check_password(user, hashedPW, HTTP_USER_AGENT, REMOTE_ADDR)
SP devuelve un código de sesión único (que se realiza mediante una combinación débil de hashing de una cadena aleatoria con los parámetros de HTTP_USER_AGENT + REMOTE_ADDR) si los hashes no coinciden o nada, si no. este código de sesión luego se almacena en una SESSION var que se utilizará en cada llamada de procedimiento almacenado a la base de datos para autenticar el acceso.
Aplicaciones PHP:
- el usuario de verificación existe en el sistema "
call check_user(user, HTTP_USER_AGENT, REMOTE_ADDR)
". - Si se encuentra
user
y la dirección no está bloqueada, DB registra la búsqueda del nombre de usuario y devuelve sal. - Si REMOTE_ADDR está bloqueado, registre y devuelva 0
- El usuario de hash ingresó la contraseña con salt y envía una cadena a la base de datos usando "
call check_password(user, hashedPW, HTTP_USER_AGENT, REMOTE_ADDR)
". - DB comprueba la lista de direcciones IP prohibidas, si el nombre de usuario, remote_addr & La coincidencia HTTP_USER_AGENT, el DB registra la autenticación sin éxito, el DB devuelve 0
- Si las cadenas coinciden, la base de datos registra la autenticación correcta, la base de datos devuelve los datos de los usuarios en la lista.
- Si las cadenas NO coinciden, la base de datos registra una autenticación sin éxito, la base de datos devuelve 0.
Razonamiento
Mi solución permite:
- El hash se realiza en PHP, lo que permite que se realice más procesamiento (¿rondas / ciclos?) en el hashing, mejores algoritmos de hashing (como Argon2).
- El usuario de SQL puede configurarse con solo permisos limitados para ejecutar procedimientos almacenados, de esta manera, incluso si el nombre de usuario y la contraseña de la conexión SQL se piratean, solo se puede usar para obtener los datos proporcionados en los procedimientos almacenados en el DB y nada más, por lo que no puede obtener una lista completa de usuarios y no puede obtener una lista completa de hashedPW.
- Los ataques de fuerza bruta pueden detectarse en el nivel de prueba de nombre de usuario y detenerse allí, lo que requiere una sola llamada de DB para bloquear los ataques de fuerza bruta.
- Al cliente se le muestra un nombre de usuario o una contraseña no válidos, independientemente de si falla
check_user
ocheck_password
.
¿Hay algún inconveniente en esta solución?
el único que puedo ver en este momento es que no puede usar [password_hash], que parece ser el método preferido.
He mirado otras respuestas a una pregunta similar (aquí: ¿Es una buena idea dejar que una base de datos realice una comprobación de contraseña? y en otros lugares), y la mayoría de las personas afirman que el hashing se realiza mejor en el código PHP, para permitir subprocesos múltiples (manejados por apache) y no atar el motor SQL con hacer cosas para las que no está realmente diseñado, por lo que se me ocurrió lo anterior ... todos los comentarios se recibieron con gratitud.
PS: aprendí PHP por primera vez hace aproximadamente 20 años, pero no lo he tocado ni a ningún otro desarrollador web en casi 10 años, así que sé suave.