¿La contraseña de hash en el lado del cliente para evitar el retraso en el servidor de juegos de un solo núcleo? [duplicar]

9

Actualmente estoy implementando un sistema de inicio de sesión simple. Me gustaría almacenar de forma segura todas las contraseñas de los usuarios en mi base de datos. Las contraseñas son los componentes más importantes. Todos los demás datos de usuario no son importantes. Si una cuenta es hackeada, siempre y cuando la contraseña no pueda resolverse está bien; Otros datos son cosas como: puntuación y fecha de creación de la cuenta.

Supongo que algunos de mis usuarios usarán la misma contraseña que utilizan para otros sitios. Por lo tanto, debo asegurarme de que la contraseña no pueda ser leída por un pirata informático potencial.

¿Puedo generar el Hash en el lado del cliente de alguna manera para evitar que cualquier pirata informático vea la contraseña real?

Antes de que digas, no debería hacerlo en el cliente. El servidor tiene un bucle de juego constante que debe ejecutarse, y no quiero que el juego se retrase cada vez que alguien registre una cuenta o intente iniciar sesión. Este enfoque tomaría parte de la carga del servidor.

EDITAR: Como esta pregunta se cerró, me gustaría explicarlo. Pasar al cliente me permite usar muchas más rondas cuando se utiliza el hash de la contraseña, ya que esto no afectará al servidor ni a la experiencia de otros usuarios de ninguna manera. Esto también hace que sea mucho más fácil evitar que un usuario envíe solicitudes de spam y ralentice el servidor.

    
pregunta Sidney de Vries 17.01.2017 - 15:14
fuente

3 respuestas

20
  

Supongo que algunos de mis usuarios usarán la misma contraseña que utilizan para otros sitios.

En el contexto de proteger la contraseña del uso en otros sitios (además del suyo), no importa si tiene la contraseña del lado del cliente o lado del servidor .

Sin embargo, dependiendo de su entorno de cliente , (es decir, los navegadores web), puede tener dificultades para encontrar una implementación (fuerte) suficientemente fuerte y bien de un Hash de contraseña lenta. (por ejemplo, Argon2 o BCrypt) Por lo tanto, su sugerencia de hashing del lado del cliente puede ser práctica solo en entornos de aplicaciones donde está disponible criptografía nativa .

Por supuesto, el hash del lado del cliente no hará nada para evitar que la contraseña se use en su sitio . Un atacante que ha robado el hash puede simplemente omitir la rutina de hash del lado del cliente y autenticarse con su servidor. (nunca confíe en el cliente) Afortunadamente, este vector de ataque se puede resolver desde el lado del servidor . (ver abajo)

  

El servidor tiene un bucle de juego constante que debe ejecutarse, y no quiero que el juego se retrase cada vez que alguien se registra en una cuenta o intenta iniciar sesión. Este enfoque tomaría parte de la carga del servidor.

Como usted sabe, tradicionalmente se recomienda el hash del lado del servidor. Si le preocupa la carga, le envío algunas sugerencias:

  1. El Factor de trabajo debe ajustarse solo para tomar ~ 100 ms en su hardware de destino. (su servidor) Entonces, eso no es realmente un gran retraso, ¿verdad? Normalmente abogo por 50ms-500ms, pero su sitio podría usar un valor más bajo y seguir siendo considerado robusto.

  2. El Hash debe estar en un hilo separado de su bucle principal del juego (async) para que el juego pueda continuar funcionando (aunque con un rendimiento ligeramente inferior) mientras el hash está calculando.

  3. Debería incluir alguna forma de DoS protection para limitar la cantidad de hashes que su servidor calcularía. Por lo general, el sitio limitaría los intentos de inicio de sesión (¿por usuario?) Para que un atacante no pudiera ejercer la fuerza bruta con eficacia. Un acelerador de este tipo evitaría el cálculo interminable de hash.

  4. Si lo desea, puede marcar la contraseña en ambos el Cliente y el Servidor , si el el entorno del cliente tiene suficiente soporte nativo . (descrito anteriormente) Luego puede salirse con un factor de trabajo aún más pequeño del lado del servidor.

    Si el lado del cliente tiene un Factor de trabajo suficientemente fuerte, entonces se vuelve razonable ejecutar solo un SHA-2 rápido (es decir, cero retraso) en el lado del servidor, y eso resolverá su problema por completo. ( gracias @HenningMakholm )

Finalmente, asegúrese de que el cliente envíe la contraseña (o hash) a través de solo HTTPS . Esto es lo más importante, ya que ningún supuesto hashing protegerá las contraseñas escritas en un sitio HTTP.

    
respondido por el George Bailey 17.01.2017 - 15:30
fuente
5

Si el objetivo es solo para proteger a los usuarios de la reutilización de la contraseña cuando la base de datos está comprometida, entonces sí, puede mover el hashing al lado del cliente.

Debe aceptar que, en general, esto no es suficiente para asegurar su aplicación. Es insuficiente porque, en general, la mayoría de estos enfoques tienen una de dos fallas:

  1. Ellos transmita un token que es "similar a una contraseña", en el sentido de que si do rompa sus suposiciones sobre HTTPS o lo que sea, puedo iniciar sesión como usted.

  2. Almacenan un token que es "similar a una contraseña", en el sentido de que si do puedo ver una fila en la tabla de usuarios, puedo iniciar sesión como eso usuario.

El primero es cualquier manipulación del lado del cliente que finalice con "luego transmito al servidor, el servidor lo hace, y el servidor compara si el hash es igual a algo en la base de datos". El segundo es característico de los esquemas de desafío-respuesta: "Te envío esta cadena, la cifras con tu clave, devuelves la versión cifrada y veo si puedo descifrarla para obtener el desafío original nuevamente".

Elegí las palabras para ese segundo caso con mucho cuidado porque revela que en realidad, puede evitar estas dos si su sistema se basa en criptografía asimétrica , claves públicas y llaves privadas Su servidor puede almacenar una clave pública si su cliente puede calcular una clave privada. Esto solía ser completamente inviable con RSA, etc. ("Oh, solo usaré la contraseña como semilla para un generador de números aleatorios determinista y realizaré la configuración de teclas cada vez". Criptografía de curva elíptica, donde la clave privada a menudo puede ser literalmente una cadena de bits arbitraria de cierta longitud. Utiliza una función de obtención de claves para obtener eso, y estás a salvo.

Sin embargo, es posible que no desee "cripto" propio en cualquier caso: en ese caso, busque una implementación del protocolo de contraseña remota segura (SRP) creado en Stanford; ha visto mucho criptoanálisis y ha existido por un tiempo y es probable que tenga implementaciones que puedas encontrar y usar.

    
respondido por el CR Drost 17.01.2017 - 16:38
fuente
3

Puede hacer la parte costosa del hash de contraseña en el lado del cliente, pero debe tener cuidado. Por ejemplo, el siguiente protocolo sería incorrecto :

  1. El cliente establece un canal autenticado y confidencial al servidor. (Por ejemplo, una conexión SSL con un certificado de servidor válido).
  2. El cliente envía username al servidor
  3. El servidor busca la entrada de contraseña correspondiente (username, salt, hashed_pwd)
  4. El servidor envía salt al cliente.
  5. El cliente tiene su contraseña con un hash de contraseña costoso: client_hash = pwhash(salt, pwd)
  6. El cliente envía client_hash al servidor.
  7. El servidor compara client_hash con hashed_pwd ; el usuario se autentica si son iguales.

Ese protocolo sería inseguro porque los hashes que almacena el servidor serían "equivalentes a una contraseña"; un pirata informático que robó la base de datos de contraseñas del servidor podría reproducir los hashes sobre el protocolo para hacerse pasar por cualquier usuario. Así que el servidor todavía necesita hacer hashing con sal ; lo que puede hacer es mover los cálculos más costosos al cliente para que el servidor solo necesite calcular un hash salado rápido.

Un mejor protocolo sería este:

  1. El cliente establece un canal autenticado y confidencial al servidor. (Por ejemplo, una conexión SSL con un certificado de servidor válido).
  2. El cliente envía username al servidor
  3. El servidor busca la entrada de contraseña correspondiente (username, client_salt, server_salt, hashed_pwd) . (Este es un paso cambiado en comparación con el protocolo incorrecto: el protocolo bueno tiene dos sales, una para el cliente, una para el servidor.)
  4. El servidor envía client_salt al cliente.
  5. El cliente tiene su contraseña con un hash de contraseña costoso: client_hash = pwhash(client_salt, pwd)
  6. El cliente envía client_hash al servidor.
  7. El servidor calcula server_hash = fast_salted_hash(server_salt, client_hash) . La función fast_salted_hash podría ser HMAC o Blake2, con la clave server_salt . (Este es un paso adicional que no existía en el protocolo incorrecto).
  8. El servidor compara server_hash con hashed_pwd ; el usuario se autentica si son iguales.

Al incluir el hash de la contraseña en el lado del cliente, significa que los usuarios que eligen la misma contraseña enviarán diferentes hashes a través del cable, de modo que un pirata informático que comprometa a un cliente y descubra que su client_hash no puede volver a jugar como usuario con la misma contraseña.

Al almacenar solo un hash con sal del client_hash , defendemos contra los atacantes que roban la base de datos de contraseñas, como en el hashing de contraseñas convencional.

    
respondido por el Luis Casillas 17.01.2017 - 20:45
fuente

Lea otras preguntas en las etiquetas