Este es principalmente un experimento mental para la comunicación cliente / servidor, y quiero conocer las fallas.
Cuando se crea una cuenta de usuario (con U
como nombre de usuario y P
como contraseña), genero un salt aleatorio ( S
) y almaceno estos valores en la base de datos (en el lado del servidor) : U
, S
y H
que se calcula como H = hash(U+S+P)
.
Al autenticar un usuario:
- El cliente primero "intenta una autenticación" enviando
U
al servidor. - El servidor crea un código de desafío (
R
) para ese usuario y lo almacena en la base de datos, junto con el tiempo en que este desafío vencería (T
) y envíaR
yS
al cliente . - El cliente calcula su propia versión de
H
(mediante la combinación de hashingU
yS
yP
juntos; tieneU
yP
, y recibióS
del servidor.) - El cliente luego calcula un nuevo valor
G
comoG = hash(H+R)
y envía esteG
nuevamente al servidor ("solicitud de autenticación" real). - El servidor tiene su propio
H
junto conR
para reconstruirG
y autentica al usuario si suG
coincide con el valor recibido del cliente yT
no ha pasado todavía. - Si la autenticación se realiza correctamente o falla,
R
se elimina de la base de datos del servidor.
Los defectos que ya conozco son estos:
- Al crear una cuenta, la contraseña se transmite en texto sin formato. Esto se puede mitigar utilizando un servicio dedicado de creación de cuentas que emplea SSL para crear cuentas.
- Intentar una autenticación dará como resultado que se asignen algunos recursos en el servidor. Esto se puede mitigar permitiendo solo uno (o un número fijo) de códigos de desafío por usuario.
- Intentar descubrir nombres de usuario y sales válidos al generar muchos intentos de autenticación; que el servidor puede frustrar al enviar un código aleatorio de sal y desafío incluso cuando el usuario no existe.
Aquí están mis preguntas específicas:
- ¿Qué me estoy perdiendo? ¡¿Dónde está el desastre esperando a suceder ?!
- ¿Qué puedo hacer para que esto sea más seguro / mejor? Aparte de usar SSL y simplemente enviar contraseñas de texto sin formato (texto sin formato solo desde la perspectiva de mi aplicación).
- Estoy pensando en SHA-256 para todos los hashes. ¿Hay algún defecto en la familia SHA-2? ¿Es hash de los valores una vez suficiente para generar
H
yG
? - Para generar
H
yG
, ¿son mejores otras permutaciones de valores? p.ej.P+U+S
,R+H
, etc. - ¿Qué ventajas estoy negando a mis usuarios? (Aparte de sus autenticaciones que ahora necesitan dos viajes de ida y vuelta al servidor).
ACTUALIZACIÓN : En última instancia, quiero hacer esto:
Después de una autenticación exitosa, el servidor genera una clave de sesión K
como: K = hash(H+F)
donde F
es una cadena aleatoria. F
se envía al usuario y K
se retiene en la base de datos. El cliente reconstruye K
utilizando el F
recibido y encripta todas las comunicaciones con el servidor en adelante con un cifrado simétrico (por ejemplo, AES) con K
como clave.