2009-10-17 22 views
92

Si en una pantalla de inicio de sesión el usuario envía un formulario con su nombre de usuario y contraseña, la contraseña se envía en texto sin formato (incluso con POST, corrígeme si estoy equivocado).¿Cómo enviar una contraseña de forma segura a través de HTTP?

Entonces, la pregunta es, ¿cuál es la forma correcta de proteger al usuario y su contraseña contra el tercero que podría estar escuchando a escondidas los datos de comunicación?

Soy consciente de que HTTPS es una solución al problema, pero ¿hay alguna forma de garantizar al menos cierto nivel de seguridad utilizando el protocolo HTTP estándar (solicitud POST)? (Tal vez usando javascript de alguna manera)

EDITAR que puede haber dejado de lado algunas cosas importantes.

Lo que me trataba era una página, es decir, la página de inicio de sesión generada por PHP, que por supuesto se envía al usuario en la solicitud HTTP GET como un archivo HTML. No hay una conexión (@Jeremy Powel) establecida entre el servidor y el cliente, por lo que no puedo crear dicho protocolo de protocolo de enlace. Y quiero que el proceso completo sea transparente para el usuario; desea enviar una contraseña, no tratar con la criptografía.

Gracias.

+0

buen punto sobre la conexión persistente. –

+1

Probablemente no podrá lograr esto sin que el cliente use la criptografía, pero el usuario no tiene que ver tal proceso. Simplemente ingresa su contraseña y el código que genera su PHP (javascript por ejemplo) maneja todo por usted. –

+9

El problema que describes es la razón por la que se inventó HTTPS. Si envía un secreto al cliente para cifrar la contraseña, un oculista podrá olfatearlo y descifrar la contraseña en el viaje de regreso. – jnoss

Respuesta

50

El uso de HTTP con SSL hará que su vida sea mucho más fácil y podrá descansar tranquilo. Personas muy inteligentes (¡más inteligentes que yo al menos!) Han analizado este método de comunicación confidencial durante años.

+8

... y * "¡Pero tengo que pagar por un certificado SSL!" * no es una queja válida, ya que puede obtenerlos por $ 30 en estos días. ¿Sus datos realmente no valen 30 dólares para proteger? – caf

+3

¿Qué sucede si el servidor web al que se suscribió no admite la adición de certificados SSL? – Calmarius

+58

@ Calmarius - luego te mueves a un verdadero servidor web – BornToCode

14

Puede usar un esquema de respuesta al desafío. Dicen que el cliente y el servidor ambos saben un secreto S. A continuación, el servidor puede estar seguro de que el cliente conoce la contraseña (sin dar a la basura) por:

  1. Server envía un número aleatorio, R, al cliente.
  2. El cliente envía H (R, S) de vuelta al servidor (donde H es una función hash criptográfica, como SHA-256)
  3. El servidor calcula H (R, S) y lo compara con la respuesta del cliente. Si coinciden, el servidor sabe que el cliente conoce la contraseña.

Editar:

Hay un problema aquí con la frescura de R y el hecho de que HTTP no tiene estado. Esto se puede manejar haciendo que el servidor cree un secreto, llámalo Q, que solo el servidor conoce. Entonces el protocolo es el siguiente:

  1. El servidor genera un número aleatorio R. Luego lo envía al cliente H (R, Q) (que no puede ser falsificado por el cliente).
  2. cliente envía R, H (R, Q), y calcula H (R, S) y envía todos de la misma de nuevo al servidor (donde H es una función hash criptográfica, como SHA-256)
  3. computa Server H (R, S) y lo compara con la respuesta del cliente. Luego toma R y calcula (nuevamente) H (R, Q). Si la versión del cliente de H (R, Q) y H (R, S) coincide con el recálculo del servidor, el servidor considera que el cliente se autenticó.

Tomar nota, ya que H (R, Q) no puede ser falsificada por el cliente, H (R, Q) actúa como una cookie (y por lo tanto podría ser implementada en realidad como una cookie).

Otra edición:

La edición anterior con el protocolo es incorrecto, ya que cualquiera que haya observado H (R, Q) parece ser capaz de jugar de nuevo con el hash correcto. El servidor debe recordar qué R ya no están frescas. Estoy buscando esta respuesta para que puedan editar todo esto y encontrar algo bueno.

+0

+1 - necesitará calcular la respuesta en el lado del cliente con javascript (o Flash/Silverlight/etc.) – orip

+0

Iba a decir lo mismo. No estoy seguro de que haya bibliotecas js para hacer esto. Será interesante seguir esta publicación. –

+0

El envío de R se puede hacer con un campo de formulario oculto (el servidor debe validar que la R recibida fue reciente y no se usó antes) – Yuliy

1

HTTPS es tan poderoso porque usa criptografía asimétrica. Este tipo de criptografía no solo le permite crear un túnel encriptado, sino que también puede verificar que está hablando con la persona adecuada y no con un pirata informático.

Aquí está el código fuente de Java que utiliza el cifrado asimétrico RSA (usado por PGP) para comunicarse: http://www.hushmail.com/services/downloads/

4

me gustaría utilizar un servidor y sistema de intercambio de claves Diffie-Hellman del lado del cliente con AJAX o múltiple Form Submit (yo recomiendo el primero), aunque no veo ninguna buena implementación del mismo en internet. Recuerde que una biblioteca JS siempre puede estar corrupta o modificada por MITM. El almacenamiento local se puede usar para ayudar a combatir esto, hasta cierto punto.

8

Si su webhost lo permite, o tendrá que tratar con datos confidenciales, entonces use HTTPS, punto. (A menudo es requerido por la ley afaik).

De lo contrario, si desea hacer algo a través de HTTP. Haría algo así.

  1. El servidor inserta su clave pública en la página de inicio de sesión.
  2. El cliente rellena el formulario de inicio de sesión y hace clic en enviar.
  3. Una solicitud AJAX obtiene la marca de tiempo actual del servidor.
  4. script del lado del cliente concatena las credenciales, la marca de tiempo y una sal (hash a partir de datos analógico por ejemplo. Los movimientos del ratón, los eventos de pulsación de teclas), cifra con la clave pública.
  5. Envía el hash resultante.
  6. El servidor descifra el hash
  7. Comprueba si la marca de tiempo es lo suficientemente reciente (solo permite una ventana corta de 5-10 segundos). Rechaza el inicio de sesión si la marca de tiempo es demasiado antigua.
  8. Almacena el hash durante 20 segundos. Rechaza el mismo hash para iniciar sesión durante este intervalo.
  9. Autentica al usuario.

De esta manera, la contraseña está protegida y el mismo hash de autenticación no se puede reproducir.

Acerca de la seguridad del token de sesión. Eso es un poco mas dificil Pero es posible hacer que reutilizar un token de sesión robado sea un poco más difícil.

  1. El servidor establece una cookie de sesión adicional que contiene una cadena aleatoria.
  2. El navegador envía esta cookie en la siguiente solicitud.
  3. El servidor comprueba el valor de la cookie, si es diferente, entonces se destruye la sesión, por lo demás todo está bien.
  4. El servidor vuelve a establecer la cookie con texto diferente.

Así que si el token de sesión nos robaron, y se envía una solicitud por otra persona, a continuación, en la siguiente petición del usuario original se destruyó la sesión. Entonces, si el usuario navega activamente por el sitio, haciendo clic en los enlaces a menudo, entonces el ladrón no irá muy lejos con el token robado. Este esquema puede fortalecerse al requerir otra autenticación para las operaciones confidenciales (como la eliminación de la cuenta).

Acerca de la aplicación: RSA es, probablemente, a algoritmo más conocido, pero es bastante lento para las claves largas. No sé qué tan rápido sería una implementación de PHP o Javascript. Pero probablemente haya algoritmos más rápidos.

+0

En este caso, ¿la contraseña está realmente protegida? ¿Alguien podría olfatear lo que se envía y descifrarlo con la clave pública y luego actualizar la marca de tiempo cuando la use más adelante? ¿Me estoy perdiendo de algo? – michaellindahl

+0

@michaellindahl El cifrado asimétrico significa que solo la clave privada, que nunca sale del servidor, se puede utilizar para descifrar cosas. Las claves públicas solo se pueden usar para encriptar. –

+0

Una computadora entre el navegador y el servidor podría cambiar la clave pública en la página de inicio de sesión. – Antti

2

Puede utilizar SRP utilizar contraseñas seguras a través de un canal inseguro. La ventaja es que incluso si un atacante olfatea el tráfico o compromete el servidor, no puede usar las contraseñas en un servidor diferente. https://github.com/alax/jsrp es una biblioteca de JavaScript que admite contraseñas seguras a través de HTTP en el navegador, o en el lado del servidor (a través del nodo).

19

Autenticación segura es un tema muy amplio. En pocas palabras, como mencionó @ jeremy-powell, siempre favorece el envío de credenciales a través de HTTPS en lugar de HTTP. Eliminará muchos dolores de cabeza relacionados con la seguridad.

TSL certificados/SSL son bastante barato en estos días. De hecho, si no quiere gastar dinero, hay un gratuito letsencrypt.org - autoridad de certificación automatizada.

Usted puede ir un paso más allá y utilizar caddyserver.com que exige letsencrypt en el fondo.

Ahora, una vez que llegamos HTTPS fuera del camino ...

Usted no debe enviar de usuario y contraseña a través de la carga útil parámetros POST o GET. Utilice una cabecera de Autorización (esquema de autenticación de acceso básico) en lugar, que se construye como sigue:

  • El nombre de usuario y contraseña se combinan en una cadena separada por un colon, por ejemplo: nombre de usuario: contraseña
  • El La cadena resultante se codifica utilizando la variante RFC2045-MIME de Base64, excepto que no se limita a 76 char/line.
  • El método de autorización y un espacio es decir, "Basic" entonces se pone antes de la cadena codificada.

fuente: Wikipedia: Authorization header

Podría parecer un poco complicado, pero no lo es. Existen muchas bibliotecas buenas que le brindarán esta funcionalidad de manera inmediata.

Hay algunas buenas razones por las que debe utilizar una cabecera de Autorización

  1. Es un estándar
  2. Es simple (después de aprender cómo usarlos)
  3. Se le permitirá hacer login a nivel de URL, así: https://user:[email protected]/login (Chrome, por ejemplo, se convertirá automáticamente en Authorization cabecera)

IMPORTANTE:
Como señala @zaph en su comentario a continuación, enviar información confidencial como una consulta GET no es una buena idea, ya que lo más probable es que termine en los registros del servidor.

enter image description here

+5

El problema con el envío de credenciales (contraseña) como parámetros GET es que el par usuario/contraseña probablemente terminará en registros del servidor, lo que no es una buena idea. Lo mejor es enviar credenciales en un POST. – zaph

+0

Ahh ... para nada. La captura de pantalla que está viendo se modifica para ilustrar lo que está sucediendo en un navegador. En el momento de presionar, el navegador convertirá su URL creando un encabezado 'Autorización'. Sólo pruébalo. Los registros te recordarán limpio. Y, por supuesto, si realiza una llamada desde el servidor (si ese es el escenario que le preocupa), debe generar el encabezado programáticamente, por supuesto. – FullStackForger

+0

No puede registrar lo que no puede ver. 'username: password @ url' del navegador se traduce a: encabezado de solicitud' url' + 'Authorization'. En cuanto a las consultas GET ... como dije, use el encabezado Authroziation. Es mejor. – FullStackForger

0

puede utilizar SSL para su anfitrión no hay proyecto libre para SSL como letsencrypt https://letsencrypt.org/

+0

Verifique la tercera oración en cuestión. (Además, siempre lea otras respuestas para asegurarse de que no está agregando un duplicado menos detallado). –

Cuestiones relacionadas