¿Cómo proteger las contraseñas a través de HTTP?

26

Di que mi contraseña es abc . Quiero enviarlo al servidor a través de HTTP.

Podría enviarlo en texto sin formato y dejar que el servidor lo triture y compararlo con las entradas en su base de datos, pero cualquier persona que pueda ver el tráfico a través de esa conexión verá la contraseña en texto sin formato.

Entonces, podría hacer un hash del lado del cliente y dejar que el servidor simplemente lo compare sin el hash ya que ya está hash (o el servidor podría incluso hacer un hash doble, pero no hay diferencia en esta situación). Pero nuevamente, cualquier persona que pueda ver el tráfico vería que la contraseña estaba oculta y luego enviaba la contraseña al servidor y el servidor la aceptaría.

¿Cómo envío contraseñas a través de HTTP? ¿Necesito implementar algún algoritmo de cifrado como el cifrado de clave pública RSA? ¿O es esto imposible?

El método debe poder utilizarse en cualquier navegador.

    
pregunta FireCubez 09.11.2018 - 14:57
fuente

10 respuestas

109

No puedes.

Para enviar información de forma segura a través de un canal no seguro, necesita cifrado.

El cifrado simétrico está fuera, porque primero necesitaría transportar la clave, lo que no puede hacer de manera segura en un canal no seguro [*].

Eso te deja con criptografía de clave pública. Por supuesto, puedes hacer tu propia , pero no quieres para ser un Dave , eso está fuera, lo que te deja con HTTPS.

[*] Por supuesto, puede intentar usar un canal seguro para intercambiar la clave, por ejemplo, el intercambio físico de una clave. Luego puede usar una clave secreta criptográfica, como Kerberos.

    
respondido por el tim 09.11.2018 - 15:08
fuente
46

TLS es realmente la única forma de hacerlo.

¿Pero qué pasa si lo cifro con JavaScript?

El atacante puede cambiar el JavaScript que le envías al cliente, o simplemente inyectar su propio JavaScript que registra toda la información ingresada.

Luego usaré CSP y SRI para evitar la adición de scripts y la modificación de mis propios scripts.

Me alegra que esté utilizando herramientas modernas para ayudar a proteger su sitio, pero SRI en un no -contexto seguro realmente solo protege contra el compromiso de un recurso externo. Un atacante puede simplemente modificar los encabezados CSP y las etiquetas SRI.

Realmente no hay forma de hacer esto sin usar cifrado desde el principio, y la única forma estándar de hacerlo es usar TLS.

    
respondido por el AndrolGenhald 09.11.2018 - 15:09
fuente
26

Aunque estoy de acuerdo en que debería usar HTTPS, puede hacerlo aún más seguro utilizando el Mecanismo de autenticación de respuesta de desafío con sal (SCRAM, consulte RFC 5802 ) para el intercambio de autenticación real.

No es trivial de implementar, pero lo esencial es que, en lugar de enviar la contraseña al servidor, envíe una prueba al servidor de que conoce la contraseña. Dado que derivar la prueba usa un nonce del cliente y el servidor, no es algo que pueda ser reutilizado por un atacante (como lo sería el envío del hash).

Esto tiene algunos beneficios adicionales al usar HTTPS con la autenticación básica que describe:

  1. El servidor nunca ve su contraseña cuando inicia sesión. Si alguien ha logrado insertar un código malicioso en el servidor, aún no sabrá cuál es su contraseña.
  2. Si hay un error en la implementación de HTTPS (piense en Heartbleed), los atacantes aún no podrán adquirir su contraseña. Porque, incluso una vez que se omite TLS, la contraseña no está disponible.
  3. Si, por alguna razón, no puede usar HTTPS, es mejor que enviar la contraseña sin cifrar. Un atacante no podrá adivinar su contraseña basándose en el intercambio. Dicho esto, aún debe utilizar HTTPS, porque la defensa en profundidad es mejor.

Tenga en cuenta que esto solo es seguro si el cliente puede realizar los cálculos de SCRAM sin descargar el código del servidor. Podría proporcionar un cliente gordo, o los usuarios podrían escribir su propio código que controlan. Descargar el código SCRAM a través de HTTP le daría a un atacante la oportunidad de modificar el código SCRAM para enviar la contraseña en texto sin cifrar, o exponerlo de otra manera.

    
respondido por el Melanie 09.11.2018 - 19:01
fuente
7

Definitivamente deberías implementar TLS en este caso.

Si decides intentar inventar un sistema de seguridad de transporte a través de HTTP, finalmente terminarás implementando un susbset de la funcionalidad TLS de todos modos. Hay muchos inconvenientes que debe tener en cuenta al diseñar e implementar un sistema de este tipo, que se amplifican aún más cuando decide intentar implementar el sistema con un lenguaje que no ofrezca muchas funciones de seguridad.

Incluso si implementó una implementación correcta de un protocolo criptográfico en JavaScript (que ya es un gran desafío), no puede confiar en que la implementación sea resistente a los ataques de temporización y todo se rompe si alguien tiene scripts deshabilitados ( por ejemplo, con NoScript).

Como regla general, debe elegir la implementación que consiste en los componentes más simples, comprensibles y confiables que requieren que escriba la menor cantidad de código crítico para la seguridad. Para citar a Andrew Tannenbaum:

  

Un número sustancial de los problemas (en la seguridad de la aplicación) son causados por un software defectuoso, que se produce porque los proveedores siguen agregando más y más funciones a sus programas, lo que inevitablemente significa más código y, por lo tanto, más errores .

    
respondido por el Polynomial 09.11.2018 - 19:31
fuente
6
  

¿Necesito implementar algún algoritmo de cifrado como el cifrado de clave pública RSA?

Si está pensando en intentarlo, también puede recorrer la milla completa y usar HTTPS. Ya que no parece ser un experto, el cifrado "enrollar su propio" sin duda tendrá implementaciones erróneas que lo harán inseguro.

    
respondido por el Brian Williams 09.11.2018 - 17:03
fuente
2

En realidad, hay una forma de autenticar a un usuario a través de una conexión insegura: Protocolo de contraseña remota segura (SRP) . SRP está diseñado específicamente para permitir que un cliente se autentique a sí mismo en un servidor sin que un atacante Man-in-the-Middle pueda capturar la contraseña del cliente, o incluso reproducir la autenticación para personificar más tarde al cliente, ya sea que la autenticación haya tenido éxito o no. Además, la autenticación exitosa con SRP crea una clave secreta compartida que tanto el cliente como el servidor conocen, pero un MitM no. Esta clave secreta podría usarse para cifrado simétrico y / o HMAC.

Sin embargo, hay una serie de limitaciones de SRP:

  1. El usuario debe haberse registrado de forma segura, ya que el proceso de registro requiere la transmisión de material equivalente a una contraseña (aunque el servidor no necesita almacenarlo).
  2. Aunque es seguro intentar un inicio de sesión SRP con un servidor que no sea de confianza (es decir, no expondrá su contraseña a ese servidor, y podrá decir que el servidor no tenía su contraseña en su base de datos), no es seguro cargar una página web de inicio de sesión desde un servidor que no sea de confianza (podría enviar una página que capture cada una de las pulsaciones y la envíe a algún lugar).
  3. Aunque la autenticación exitosa a través de SRP genera una clave secreta compartida segura, el código para usar realmente esta clave en una aplicación web debería cargarse desde un servidor, y un atacante podría manipular ese código para robar la clave simétrica y hacer Cambios en las solicitudes y respuestas.

En otras palabras, mientras que SRP puede ser útil en situaciones en las que tiene un cliente confiable que no necesita descargar su código a través de la conexión insegura y también tiene otra forma segura de registrar el usuario (s), SRP no es adecuado para una aplicación web. Las aplicaciones web siempre descargan su código del servidor, por lo que si la conexión al servidor no es segura, un MitM (u otro atacante de la red, por ejemplo, alguien que falsifica DNS) puede inyectar código malicioso en la aplicación web y no hay nada que usted, La víctima, puede hacerlo al respecto. Una vez que el código está allí, puede capturar cualquier contraseña u otros datos que ingrese, robar cualquier clave que se genere y manipular las solicitudes que envíe o las respuestas que reciba sin que usted lo sepa.

    
respondido por el CBHacking 10.11.2018 - 11:42
fuente
2

En realidad es bastante posible.

La contraseña debe estar oculta en el lado del cliente, pero no con una función estática. El siguiente método utiliza dos pasos y está inspirado en la Autenticación de acceso de resumen :

NOTA: El servidor mantiene un HMAC de la Contraseña y la correspondiente Clave ( Recopilación );

  1. El cliente comienza solicitando un nonce al servidor, el servidor devuelve la Clave y el Nonce ;
  2. El cliente calcula: HMAC (HMAC ( Contraseña , Clave ), Nonce ) y lo envía al servidor;
  3. El servidor calcula: HMAC ( Digest , Nonce ) y lo compara con el valor recibido.

Esto te protege contra la reproducción.

El interés principal que veo no es una protección contra las escuchas ilegales, pero para estar completamente seguro de que la contraseña de texto simple no se almacenará en el servidor, ni siquiera en un registro del sistema (consulte Twitter o GitHub ).

Nota: HMAC se puede reemplazar por PBKDF2.

    
respondido por el Pierre del Perugia 10.11.2018 - 10:38
fuente
1

Ciertamente es posible enviar una contraseña de forma segura utilizando HTTP. Incluso hay un estándar para ello. Se llama HTTP-Digest y se define en RFC 7616. Ha sido parte de la especificación HTTP durante bastante tiempo. Originalmente, fue diseñado para usar solo el algoritmo de resumen de mensajes ("hashing") MD5, pero las revisiones posteriores del estándar permiten al cliente y al servidor negociar qué algoritmo usar.

Desafortunadamente, hay muchos problemas con el resumen de HTTP y el más evidente de ellos es que el servidor necesita tener la contraseña en texto claro . Por lo tanto, aunque es posible comunicar las contraseñas de forma segura mediante HTTP, no es posible almacenar de forma segura las contraseñas en el servidor mientras se usan. Así que, básicamente, no es útil.

Como han dicho otros, sería mejor implementar TLS porque resuelve múltiples problemas al mismo tiempo, y es bastante compatible con el futuro.

    
respondido por el Christopher Schultz 10.11.2018 - 23:51
fuente
1

Como han dicho otros TLS! TLS! TLS! (y con una longitud de clave decente también)

Pero si tiene que usar HTTP y cualquier servidor para implementar, ¿esto es para uso programático o humano? Si es para uso humano, ¿está buscando una autenticación básica o basada en formularios? Y son sus usos capaces de aplicar un poco de lógica, por ejemplo, no es para uso público. ¿Hay que proteger algo más o solo la contraseña?

Si es así, puedes mirar:

  • Use un teclado / generador de contraseña de un solo uso (los controles RSA no son baratos, y si tiene ese tipo de dinero para gastar, entonces puede pagar TLS)
  • Alguna otra autenticación de 2 factores como SMS (no sin sus propios problemas).
  • Un simple mecanismo de desafío / respuesta para ofuscar la contraseña, por ejemplo, la página muestra dos números en ella en el texto (no está claramente etiquetado), el usuario debe iniciar la contraseña con un cálculo simple, como la diferencia entre los dos números agregados a cada dígito de un PIN, tal vez con elementos aleatorios antes y / o después, por ejemplo, 98634572dkkgdld. Cambiar los números de desafío debería detener los ataques de repetición que no se intentan de manera instantánea, pero si un atacante puede capturar suficientes intentos, puede ser capaz de resolverlo. No puede poner ninguna lógica de ofuscación en el script de cara al usuario, ya que se verá y si el esquema es demasiado complejo, sus usuarios lo odiarán aún más.

Aún así, con TLS, los certificados son baratos (incluso gratuitos) en estos días, por lo que los esquemas complicados de ofuscación ya no tienen por qué existir.

    
respondido por el user211198 12.11.2018 - 22:55
fuente
-4

Necesitas que el destinatario te envíe su clave. No puede enviar aleatoriamente información cifrada a alguien sin que primero le proporcione su clave pública personal.

    
respondido por el Tomachi 11.11.2018 - 02:58
fuente

Lea otras preguntas en las etiquetas