La guía definitiva para la autenticación de sitios web basada en formularios

Autenticación basada en formularios para sitios web

Creemos que Stack Overflow no debe ser solo un recurso para preguntas técnicas muy específicas, sino también para pautas generales sobre cómo resolver variaciones en problemas comunes. La “autenticación basada en formularios para sitios web” debería ser un buen tema para dicho experimento.

Debe incluir temas tales como:

  • Cómo iniciar sesión
  • Cómo desconectarse
  • Cómo permanecer conectado
  • Gestión de cookies (incluida la configuración recomendada)
  • Cifrado SSL / HTTPS
  • Cómo almacenar contraseñas
  • Usando preguntas secretas
  • Olvidé mi nombre de usuario / contraseña
  • Uso de nonces para evitar falsificaciones de solicitudes entre sitios (CSRF)
  • OpenID
  • Casilla “Recordarme”
  • Autocompletado del navegador de nombres de usuario y contraseñas
  • URL secretas ( URL pública protegida por resumen)
  • Comprobando la fortaleza de la contraseña
  • Validación de correo electrónico
  • y mucho más sobre autenticación basada en formularios …

No debe incluir cosas como:

  • Roles y autorización
  • Autenticación HTTP básica

Por favor ayúdenos por:

  1. Sugerir subtemas
  2. Presentando buenos artículos sobre este tema
  3. Editando la respuesta oficial

PARTE I: Cómo iniciar sesión

Supondremos que ya sabe cómo crear un formulario HTML de inicio de sesión + contraseña que PUBLICA los valores a un script en el lado del servidor para la autenticación. Las siguientes secciones se ocuparán de los patrones de autenticación práctica sólida y de cómo evitar las dificultades de seguridad más comunes.

¿HTTPS o no a HTTPS?

A menos que la conexión ya sea segura (es decir, en túnel mediante HTTPS utilizando SSL / TLS), sus valores de formulario de inicio de sesión se enviarán en texto claro, lo que permite a cualquier persona que escuche en la línea entre el navegador y el servidor web leer los inicios de sesión mediante. Este tipo de escuchas telefónicas se realiza de forma rutinaria por parte de los gobiernos, pero en general no abordaremos los cables de ‘propiedad’ excepto para decir esto: si está protegiendo algo importante, use HTTPS.

En esencia, la única forma práctica de protegerse contra escuchas telefónicas / detección de paquetes durante el inicio de sesión es mediante el uso de HTTPS u otro esquema de cifrado basado en certificados (por ejemplo, TLS ) o un esquema de desafío-respuesta probado y probado (por ejemplo, el Diffie-Hellman basado en SRP). Cualquier otro método puede ser eludido fácilmente por un atacante que esté escuchando.

Por supuesto, si está dispuesto a ser un poco práctico, también podría emplear algún tipo de esquema de autenticación de dos factores (por ejemplo, la aplicación Google Authenticator, un libro de códigos físico de “estilo de guerra fría” o un dongle generador de claves RSA). Si se aplica correctamente, esto podría funcionar incluso con una conexión no segura, pero es difícil imaginar que un desarrollador esté dispuesto a implementar autenticación de dos factores, pero no SSL.

(No) Transfiere tu propio cifrado / hash de JavaScript

Dado el costo no nulo y la dificultad técnica percibida de configurar un certificado SSL en su sitio web, algunos desarrolladores están tentados de implementar sus propios esquemas de cifrado o hash en el navegador para evitar pasar inicios de sesión sin cifrar a través de un cable no seguro.

Si bien este es un pensamiento noble, es esencialmente inútil (y puede ser un defecto de seguridad ) a menos que se combine con uno de los anteriores, es decir, asegurar la línea con una encriptación fuerte o usar una respuesta de desafío comprobada. mecanismo (si no sabe qué es eso, solo sepa que es uno de los conceptos más difíciles de probar, más difíciles de diseñar y más difíciles de implementar en seguridad digital).

Si bien es cierto que hash la contraseña puede ser efectiva contra la divulgación de contraseñas , es vulnerable a ataques de repetición, ataques / secuestros Man-In-The-Middle (si un atacante puede inyectar unos pocos bytes en su página HTML no segura antes de que llegue a su navegador, simplemente pueden comentar el hash en JavaScript) o ataques de fuerza bruta (ya que le está entregando al atacante tanto el nombre de usuario, como la contraseña de hash y de sal).

CAPTCHAS contra la humanidad

Los CAPTCHA están destinados a frustrar una categoría específica de ataque: prueba automatizada de diccionario / fuerza bruta sin operador humano. No hay duda de que esta es una amenaza real, sin embargo, hay maneras de lidiar con ella a la perfección que no requieren un CAPTCHA, específicamente esquemas de aceleración de inicio de sesión en el servidor debidamente diseñados – los discutiremos luego.

Sepa que las implementaciones de CAPTCHA no se crean de la misma manera; a menudo no son solucionables por humanos, la mayoría de ellos son ineficaces contra los bots, todos son ineficaces contra la mano de obra barata del tercer mundo (según OWASP , la tasa actual de explotación es de $ 12 por cada 500 pruebas), y algunas implementaciones pueden ser técnicamente ilegal en algunos países (ver la Hoja de referencia de autenticación de OWASP ). Si debe usar un CAPTCHA, use el reCAPTCHA de Google, ya que es resistente al OCR por definición (ya que utiliza escaneos de libros clasificados por OCR) y se esfuerza por ser fácil de usar.

Personalmente, tiendo a pensar que CAPTCHAS es molesto, y los uso solo como último recurso cuando un usuario no ha podido iniciar sesión varias veces y las demoras de aceleración se ven maximizadas. Esto sucederá en raras ocasiones para ser aceptable, y fortalece el sistema como un todo.

Almacenamiento de contraseñas / Verificación de inicios de sesión

Esto finalmente puede ser de conocimiento común después de todos los hacks altamente publicitados y fugas de datos de usuario que hemos visto en los últimos años, pero debe decirse: No almacene contraseñas en texto claro en su base de datos. Las bases de datos de los usuarios se piratean, filtran o extraen rutinariamente a través de la inyección de SQL, y si está almacenando contraseñas en texto sin formato, eso es un juego instantáneo para su seguridad de inicio de sesión.

Entonces, si no puede almacenar la contraseña, ¿cómo verifica que la combinación de inicio de sesión y contraseña PUBLICADA desde el formulario de inicio de sesión sea correcta? La respuesta es hash usando una función de derivación de tecla . Cada vez que se crea un nuevo usuario o se cambia una contraseña, se toma la contraseña y se ejecuta a través de un KDF, como Argon2, bcrypt, scrypt o PBKDF2, convirtiendo la contraseña de texto claro (“correcthorsebatterystaple”) en una larga cadena de aspecto aleatorio , que es mucho más seguro almacenar en su base de datos. Para verificar un inicio de sesión, ejecuta la misma función hash en la contraseña ingresada, esta vez transfiere la sal y compara la cadena hash resultante con el valor almacenado en su base de datos. Argon2, brypt y scrypt almacenan la sal con el hash ya. Consulte este artículo en sec.stackexchange para obtener información más detallada.

La razón por la que se utiliza una sal es porque el hash en sí mismo no es suficiente; querrás agregar una llamada ‘sal’ para proteger el hash contra las tablas del arcoíris . Una sal evita efectivamente que dos contraseñas que coincidan exactamente se almacenen como el mismo valor hash, evitando que toda la base de datos se analice en una ejecución si un atacante está ejecutando un ataque de adivinación de contraseñas.

No se debe usar un hash criptográfico para el almacenamiento de contraseñas porque las contraseñas seleccionadas por el usuario no son lo suficientemente fuertes (es decir, no contienen suficiente entropía) y un atacante con acceso a los hashes puede completar un ataque de adivinación de contraseñas. Esta es la razón por la que se usa un KDF: estos “alargan la llave” de manera efectiva, lo que significa que cada contraseña que adivina un atacante implica iterar el algoritmo de hash varias veces, por ejemplo 10,000 veces, haciendo que la contraseña del atacante adivine 10,000 veces más despacio.

Datos de sesión: “has iniciado sesión como Spiderman69”

Una vez que el servidor ha verificado el inicio de sesión y la contraseña en su base de datos de usuarios y ha encontrado una coincidencia, el sistema necesita una forma de recordar que el navegador se ha autenticado. Este hecho solo debería almacenarse en el lado del servidor en los datos de la sesión.

Si no está familiarizado con los datos de la sesión, así es cómo funciona: una cadena generada aleatoriamente se almacena en una cookie que expira y se utiliza para hacer referencia a una colección de datos, los datos de la sesión, que se almacenan en el servidor. Si está usando un marco MVC, esto ya se maneja sin dudas.

Si es posible, asegúrese de que la cookie de sesión tenga los indicadores seguros y de solo HTTP establecidos cuando se envíen al navegador. El indicador httponly proporciona cierta protección contra la cookie que se lee con un ataque XSS. El indicador de seguridad garantiza que la cookie solo se envíe de vuelta a través de HTTPS y, por lo tanto, protege contra los ataques de detección de red. El valor de la cookie no debe ser predecible. Cuando se presente una cookie que hace referencia a una sesión inexistente, su valor debe reemplazarse inmediatamente para evitar la fijación de la sesión .

PARTE II: Cómo permanecer conectado – La infame checkbox “Recordarme”

Las cookies de inicio de sesión persistentes (funcionalidad “recordarme”) son una zona de peligro; por un lado, son completamente tan seguros como los inicios de sesión convencionales cuando los usuarios entienden cómo manejarlos; y, por otro lado, representan un enorme riesgo de seguridad en manos de usuarios descuidados, que pueden utilizarlos en computadoras públicas y olvidarse de cerrar la sesión, y que pueden no saber qué son las cookies del navegador o cómo eliminarlas.

Personalmente, me gustan los inicios de sesión persistentes para los sitios web que visito con regularidad, pero sé cómo manejarlos de manera segura. Si está seguro de que sus usuarios saben lo mismo, puede usar los inicios de sesión persistentes con la conciencia limpia. De lo contrario, puede suscribirse a la filosofía de que los usuarios descuidados con sus credenciales de inicio de sesión se encargarán de ellos si son pirateados. No es como si fuéramos a las casas de nuestros usuarios y arrancáramos todas esas notas Post-it que inducen palmas con contraseñas que han alineado en el borde de sus monitores, tampoco.

Por supuesto, algunos sistemas no pueden darse el lujo de tener una cuenta pirateada; para tales sistemas, no hay forma de que pueda justificar tener inicios de sesión persistentes.

Si decide implementar cookies de inicio de sesión persistentes, así es como lo hace:

  1. Primero, tómese un tiempo para leer el artículo de Paragon Initiative sobre el tema. Tendrá que obtener un montón de elementos correctos, y el artículo hace un excelente trabajo al explicar cada uno.

  2. Y solo para reiterar una de las trampas más comunes, NO ALMACENE LA PERSONALIZADA COOKIE DE INICIO DE SESIÓN (TOKEN) EN SU BASE DE DATOS, ¡SOLO UN ASPECTO DE TI! El token de inicio de sesión es Equivalente de contraseña, por lo que si un atacante tiene en sus manos su base de datos, podrían usar los tokens para iniciar sesión en cualquier cuenta, como si fueran combinaciones de inicio de sesión y contraseña de texto claro. Por lo tanto, usar hash (de acuerdo con https://security.stackexchange.com/a/63438/5002 un hash débil funcionará bien para este propósito) cuando se almacenan tokens de inicio de sesión persistentes.

PARTE III: Uso de preguntas secretas

No implemente ‘preguntas secretas’ . La función de ‘preguntas secretas’ es un anti patrón de seguridad. Lea el documento del enlace número 4 de la lista DEBE LEER. Puede preguntarle a Sarah Palin sobre eso, después de su Yahoo! la cuenta de correo electrónico fue pirateada durante una campaña presidencial anterior porque la respuesta a su pregunta de seguridad fue … “Wasilla High School”!

Incluso con preguntas especificadas por el usuario, es muy probable que la mayoría de los usuarios elijan:

  • Una pregunta secreta ‘estándar’ como el apellido de soltera o la mascota favorita de la madre

  • Una simple pieza de trivia que cualquiera podría sacar de su blog, perfil de LinkedIn o similar

  • Cualquier pregunta que sea más fácil de responder que adivinar su contraseña. Cuál, para cualquier contraseña decente, es cada pregunta que puedes imaginar

En conclusión, las preguntas de seguridad son intrínsecamente inseguras en prácticamente todas sus formas y variaciones, y no deberían emplearse en un esquema de autenticación por ningún motivo.

La verdadera razón por la cual las preguntas de seguridad aún existen en la naturaleza es que convenientemente ahorran el costo de unas pocas llamadas de soporte de usuarios que no pueden acceder a su correo electrónico para obtener un código de reactivación. Esto a expensas de la seguridad y la reputación de Sarah Palin. ¿Vale la pena? Probablemente no.

PARTE IV: Funcionalidad de contraseña olvidada

Ya mencioné por qué nunca debes usar preguntas de seguridad para manejar contraseñas de usuario olvidadas / perdidas; tampoco es necesario decir que nunca debe enviar por correo electrónico a los usuarios sus contraseñas reales. Existen al menos dos peligros más comunes para evitar en este campo:

  1. No restablezca una contraseña olvidada a una contraseña segura autogenerada: estas contraseñas son notoriamente difíciles de recordar, lo que significa que el usuario debe cambiarlas o escribirlas, por ejemplo, en un color amarillo shiny Post-It en el borde de su monitor. En lugar de establecer una nueva contraseña, simplemente deje que los usuarios elijan una nueva de inmediato, que es lo que quieren hacer de todos modos. (Una excepción a esto podría ser si los usuarios utilizan universalmente un administrador de contraseñas para almacenar / administrar contraseñas que normalmente serían imposibles de recordar sin anotarlo).

  2. Siempre hash el código / token de contraseña perdido en la base de datos. OTRA VEZ , este código es otro ejemplo de Equivalente de contraseña, por lo que DEBE ser hash en caso de que un atacante tenga en sus manos su base de datos. Cuando se solicita un código de contraseña perdido, envíe el código de texto claro a la dirección de correo electrónico del usuario, luego cópielo, guarde el hash en su base de datos y deseche el original . Al igual que una contraseña o un token de inicio de sesión persistente.

Una nota final: siempre asegúrese de que su interfaz para ingresar el ‘código de contraseña perdida’ sea al menos tan segura como su formulario de inicio de sesión, o un atacante simplemente usará esto para obtener acceso en su lugar. Asegurarse de generar “códigos de contraseña perdidos” muy largos (por ejemplo, 16 caracteres alfanuméricos sensibles a las mayúsculas y minúsculas) es un buen comienzo, pero considere agregar el mismo esquema de aceleración que el propio formulario de inicio de sesión.

PARTE V: Comprobación de la fortaleza de la contraseña

Primero, querrá leer este pequeño artículo para una verificación de la realidad: las 500 contraseñas más comunes

Bien, quizás la lista no sea la lista canónica de las contraseñas más comunes en cualquier sistema en cualquier lugar , pero es una buena indicación de lo mal que la gente elegirá sus contraseñas cuando no haya una política implementada. Además, la lista se ve espantosamente cerca de su hogar cuando la compara con análisis públicamente disponibles de contraseñas recientemente robadas.

Entonces: sin requisitos mínimos de seguridad de contraseñas, el 2% de los usuarios usa una de las 20 contraseñas más comunes. Significado: si un atacante obtiene solo 20 bashs, 1 de cada 50 cuentas en su sitio web serán crackables.

Frustrar esto requiere calcular la entropía de una contraseña y luego aplicar un umbral. La publicación especial 800-63 del Instituto Nacional de Estándares y Tecnología (NIST) tiene un conjunto de muy buenas sugerencias. Eso, cuando se combina con un análisis de diseño de diccionario y teclado (por ejemplo, ‘qwertyuiop’ es una contraseña incorrecta), puede rechazar el 99% de todas las contraseñas mal seleccionadas a un nivel de 18 bits de entropía. Simplemente calcular la fortaleza de la contraseña y mostrar un medidor de fuerza visual a un usuario es bueno, pero insuficiente. A menos que se haga cumplir, muchos usuarios lo ignorarán.

Y para una versión refrescante de la facilidad de uso de las contraseñas de alta entropía, se recomienda encarecidamente Password Strength xkcd de Randall Munroe.

PARTE VI: Mucho más – O: Prevención de bashs de inicio de sesión de fuego rápido

Primero, eche un vistazo a los números: velocidades de recuperación de contraseña: ¿por cuánto tiempo se pondrá de pie su contraseña?

Si no tiene tiempo para revisar las tablas en ese enlace, esta es la lista de ellas:

  1. No hace falta prácticamente ningún tiempo para descifrar una contraseña débil, incluso si la descifra con un ábaco

  2. No requiere prácticamente tiempo para descifrar una contraseña alfanumérica de 9 caracteres, si es insensible a mayúsculas / minúsculas

  3. No se necesita prácticamente tiempo para descifrar una contraseña de mayúsculas y minúsculas intrincada, símbolos y letras y números, si tiene menos de 8 caracteres (una PC de escritorio puede buscar en todo el espacio de teclado hasta 7 caracteres en una cuestión de días o incluso horas)

  4. Sin embargo, tomaría una cantidad de tiempo desmesurada para descifrar incluso una contraseña de 6 caracteres, ¡ si estuviera limitado a un bash por segundo!

Entonces, ¿qué podemos aprender de estos números? Bueno, muchos, pero podemos centrarnos en la parte más importante: el hecho de que prevenir un gran número de bashs de inicio de sesión sucesivos de disparos rápidos (es decir, el ataque de fuerza bruta ) realmente no es tan difícil. Pero prevenirlo correctamente no es tan fácil como parece.

En términos generales, tiene tres opciones que son efectivas contra ataques de fuerza bruta (y ataques de diccionario, pero dado que ya está empleando una política sólida de contraseñas, no deberían ser un problema) :

  • Presente un CAPTCHA después de N bashs fallidos (molesto como el infierno y, a menudo ineficaz, pero me estoy repitiendo aquí)

  • Bloqueando cuentas y requiriendo verificación de correo electrónico después de N bashs fallidos (este es un ataque DoS esperando a suceder)

  • Y, por último, la limitación de inicio de sesión : es decir, establecer un retraso entre bashs después de N bashs fallidos (sí, los ataques DoS todavía son posibles, pero al menos son mucho menos probables y mucho más complicados de lograr).

Práctica recomendada n. ° 1: un breve retraso que aumenta con el número de bashs fallidos, como:

  • 1 bash fallido = sin demora
  • 2 bashs fallidos = 2 segundos de retraso
  • 3 bashs fallidos = retraso de 4 segundos
  • 4 bashs fallidos = 8 segundos de retraso
  • 5 bashs fallidos = 16 segundos de retraso
  • etc.

DoS atacar este esquema sería muy poco práctico, ya que el tiempo de locking resultante es ligeramente mayor que la sum de los tiempos de locking anteriores.

Para aclarar: la demora no es un retraso antes de devolver la respuesta al navegador. Es más como un tiempo de espera o período refractario durante el cual los bashs de inicio de sesión a una cuenta específica o desde una dirección IP específica no serán aceptados ni evaluados en absoluto. Es decir, las credenciales correctas no volverán en un inicio de sesión exitoso, y las credenciales incorrectas no provocarán un aumento de la demora.

Práctica recomendada n. ° 2: una demora de duración media que entra en vigor después de N bashs fallidos, como:

  • 1-4 bashs fallidos = sin demora
  • 5 bashs fallidos = 15-30 minutos de retraso

DoS atacar este esquema sería bastante poco práctico, pero ciertamente factible. Además, podría ser relevante tener en cuenta que un retraso tan largo puede ser muy molesto para un usuario legítimo. A los usuarios olvidados no les gustará.

Práctica recomendada n. ° 3: combinación de los dos enfoques, ya sea un retraso de tiempo fijo y corto que entre en vigor después de N bashs fallidos, como:

  • 1-4 bashs fallidos = sin demora
  • 5 bashs fallidos = 20 segundos de retraso

O bien, un retraso creciente con un límite superior fijo, como:

  • 1 bash fallido = 5 segundos de retraso
  • 2 bashs fallidos = 15 segundos de retraso
  • 3+ bashs fallidos = 45 segundos de retraso

Este esquema final fue tomado de las sugerencias de mejores prácticas de OWASP (enlace 1 de la lista DEBE LEER), y se debe considerar la mejor práctica, incluso si se admite que está en el lado restrictivo.

Sin embargo, como regla general, diría que, cuanto más sólida sea su política de contraseñas, menos tendrá que molestar a los usuarios con retrasos. Si necesita contraseñas fuertes (números alfanuméricos sensibles a las mayúsculas y minúsculas + símbolos) de más de 9 caracteres, podría darles a los usuarios 2-4 bashs de contraseña no retardada antes de activar la aceleración.

El ataque DoS a este esquema de limitación de inicio de sesión final sería muy poco práctico. Y como toque final, siempre permita que los inicios de sesión persistentes (cookies) (y / o un formulario de inicio de sesión verificado por CAPTCHA) pasen, para que los usuarios legítimos ni siquiera se retrasen mientras el ataque está en progreso . De esta forma, el muy poco práctico ataque DoS se convierte en un ataque extremadamente poco práctico.

Además, tiene sentido hacer una aceleración más agresiva en las cuentas de administrador, ya que esos son los puntos de entrada más atractivos.

PARTE VII: Ataques de fuerza bruta distribuidos

Solo como un lado, los atacantes más avanzados intentarán eludir el límite de inicio de sesión “difundiendo sus actividades”:

  • Distribuir los bashs en una botnet para evitar marcar la dirección IP

  • En lugar de elegir un usuario y probar las 50,000 contraseñas más comunes (que no pueden, debido a nuestra aceleración), escogerán LA contraseña más común y la probarán contra 50,000 usuarios en su lugar. De esta forma, no solo logran evitar las medidas de máximo bash como los CAPTCHA y la aceleración de inicio de sesión, también aumentan sus posibilidades de éxito, ya que la contraseña número 1 más común es mucho más probable que el número 49.995.

  • Espaciar las solicitudes de inicio de sesión para cada cuenta de usuario, por ejemplo, con 30 segundos de diferencia, para escabullirse por debajo del radar

Aquí, la mejor práctica sería registrar el número de inicios de sesión fallidos, en todo el sistema , y utilizar un promedio continuo de la frecuencia de inicio de sesión incorrecta de su sitio como base para un límite superior que luego impondrá a todos los usuarios.

Demasiado abstracto? Déjame reformular:

Supongamos que su sitio ha tenido un promedio de 120 inicios de sesión incorrectos por día en los últimos 3 meses. Usando eso (promedio de ejecución), su sistema puede establecer el límite global en 3 veces eso, es decir. 360 bashs fallidos durante un período de 24 horas. Luego, si el número total de bashs fallidos en todas las cuentas excede ese número en un día (o incluso mejor, supervisa la velocidad de aceleración y dispara en un umbral calculado), activa la limitación de inicio de sesión en todo el sistema, lo que significa pequeños retrasos para TODOS los usuarios (aún, a excepción de los inicios de sesión de cookies y / o los inicios de sesión CAPTCHA de respaldo).

También publiqué una pregunta con más detalles y una muy buena discusión sobre cómo evitar las trampas difíciles al defenderse de los ataques de fuerza bruta distribuidos.

PARTE VIII: Autenticación de dos factores y proveedores de autenticación

Las credenciales pueden verse comprometidas, ya sea por exploits, contraseñas que se anoten o pierdan, por el robo de las computadoras portátiles o por el ingreso de usuarios a los sitios de phishing. Los inicios de sesión pueden protegerse aún más con autenticación de dos factores, que utilizan factores fuera de banda, como códigos de un solo uso recibidos de una llamada telefónica, mensaje SMS, aplicación o dongle. Varios proveedores ofrecen servicios de autenticación de dos factores.

La autenticación se puede delegar por completo a un servicio de inicio de sesión único, donde otro proveedor maneja la recolección de credenciales. Esto lleva el problema a un tercero confiable. Google y Twitter ofrecen servicios SSO basados ​​en estándares, mientras que Facebook ofrece una solución propietaria similar.

DEBE LEER ENLACES Acerca de la autenticación web

  1. Guía de Autentificación / Autentificación OWASP de OWASP
  2. Lo que se debe y no se debe hacer con la autenticación de clientes en la web (documento de investigación muy legible del MIT)
  3. Wikipedia: cookie HTTP
  4. Preguntas de conocimiento personal para la autenticación alternativa: preguntas de seguridad en la era de Facebook (documento de investigación de Berkeley muy legible)

Artículo definitivo

Enviando credenciales

La única manera práctica de enviar credenciales de forma 100% segura es mediante el uso de SSL . Usar JavaScript para cifrar la contraseña no es seguro. Errores comunes para el hash de contraseñas del lado del cliente:

  • Si la conexión entre el cliente y el servidor no está encriptada, todo lo que haces es vulnerable a los ataques man-in-the-middle . Un atacante podría reemplazar el javascript entrante para romper el hash o enviar todas las credenciales a su servidor, podría escuchar las respuestas del cliente y hacerse pasar por los usuarios a la perfección, etc. etc. SSL con Autoridades de certificación de confianza está diseñado para prevenir ataques MitM.
  • La contraseña hash recibida por el servidor es menos segura si no realiza un trabajo redundante adicional en el servidor.

Hay otro método seguro llamado SRP , pero está patentado (aunque tiene licencia libre ) y hay pocas implementaciones disponibles.

Almacenamiento de contraseñas

Nunca almacene contraseñas como texto sin formato en la base de datos. Ni siquiera si no le importa la seguridad de su propio sitio. Asum que algunos de sus usuarios reutilizarán la contraseña de su cuenta bancaria en línea. Por lo tanto, almacene la contraseña hash y deseche el original. Y asegúrese de que la contraseña no aparezca en los registros de acceso o de la aplicación. OWASP recomienda el uso de Argon2 como su primera opción para nuevas aplicaciones. Si no está disponible, se debe usar PBKDF2 o scrypt en su lugar. Y finalmente, si ninguno de los anteriores está disponible, use bcrypt.

Los hash por sí mismos también son inseguros. Por ejemplo, las contraseñas idénticas significan hashes idénticos: esto hace que las tablas de búsqueda de hash sean una forma efectiva de descifrar muchas contraseñas al mismo tiempo. En cambio, almacena el hash salado . Una sal es una cadena adjunta a la contraseña antes de la mezcla: use una sal diferente (aleatoria) por usuario. La sal es un valor público, por lo que puede almacenarlos con el hash en la base de datos. Mira aquí para más sobre esto.

Esto significa que no puede enviar al usuario sus contraseñas olvidadas (porque solo tiene el hash). No restablezca la contraseña del usuario a menos que haya autenticado al usuario (los usuarios deben demostrar que pueden leer los correos electrónicos enviados a la dirección de correo electrónico almacenada (y validada)).

Preguntas de seguridad

Las preguntas de seguridad son inseguras; evite usarlas. ¿Por qué? Cualquier cosa que haga una pregunta de seguridad, una contraseña es mejor. Lea la PARTE III: Usar preguntas secretas en la respuesta de @Jens Roland aquí en esta wiki.

Cookies de sesión

Después de que el usuario inicia sesión, el servidor envía al usuario una cookie de sesión. El servidor puede recuperar el nombre de usuario o ID de la cookie, pero nadie más puede generar dicha cookie (TODO explicar los mecanismos).

Las cookies pueden ser secuestradas : solo son tan seguras como el rest de la máquina del cliente y otras comunicaciones. Se pueden leer desde el disco, detectarse en el tráfico de la red, eliminarse mediante un ataque de secuencias de comandos entre sitios, detectarse un DNS envenenado para que el cliente envíe sus cookies a los servidores incorrectos. No envíe cookies persistentes. Las cookies deben caducar al final de la sesión del cliente (el navegador se cierra o abandona su dominio).

Si desea autenticar a sus usuarios, puede establecer una cookie persistente, pero debe ser distinta de una cookie de sesión completa. Puede establecer un indicador adicional que el usuario ha iniciado sesión automáticamente y necesita iniciar sesión para operaciones confidenciales reales. Esto es popular entre los sitios de compras que desean ofrecerle una experiencia de compra personalizada y sin problemas, pero aún así proteger sus detalles financieros. Por ejemplo, cuando regresa a visitar Amazon, le muestran una página que parece haber iniciado sesión, pero cuando va a realizar un pedido (o cambia su dirección de envío, tarjeta de crédito, etc.), le piden que confirme tu contraseña.

Los sitios web financieros, como bancos y tarjetas de crédito, por otro lado, solo tienen datos confidenciales y no deben permitir el inicio de sesión automático o un modo de baja seguridad.

Lista de recursos externos

  • Qué hacer y qué no hacer de autenticación de cliente en la Web (PDF)
    Artículo académico de 21 páginas con muchos consejos geniales.
  • Pregunte a YC: mejores prácticas para la autenticación de usuario
    Discusión del foro sobre el tema
  • Probablemente está almacenando contraseñas incorrectamente
    Artículo introductorio sobre el almacenamiento de contraseñas
  • Discusión: Horror de encoding: Probablemente está almacenando contraseñas incorrectamente
    Discusión del foro sobre un artículo de Coding Horror.
  • ¡Nunca almacene contraseñas en una base de datos!
    Otra advertencia sobre el almacenamiento de contraseñas en la base de datos.
  • Agrietamiento de contraseña
    Artículo de Wikipedia sobre las debilidades de varios esquemas de hash de contraseñas.
  • Suficiente con The Rainbow Tables: lo que debe saber sobre los esquemas de contraseña segura
    Discusión sobre tablas de arcoiris y cómo defenderse de ellas y contra otros hilos. Incluye una amplia discusión.

Primero, una fuerte advertencia de que esta respuesta no es la más adecuada para esta pregunta exacta. ¡Definitivamente no debería ser la mejor respuesta!

Continuaré y mencionaré el BrowserID propuesto por Mozilla (o quizás más precisamente, el Verified Email Protocol ) en el espíritu de encontrar una ruta de actualización para mejores enfoques de autenticación en el futuro.

Lo resumiré de esta manera:

  1. Mozilla es una organización sin fines de lucro con valores que se alinean bien con la búsqueda de soluciones para este problema.
  2. La realidad actual es que la mayoría de los sitios web usan autenticación basada en formularios
  3. La autenticación basada en formularios tiene un gran inconveniente, que es un mayor riesgo de phishing . Se solicita a los usuarios que ingresen información sensible en un área controlada por una entidad remota, en lugar de un área controlada por su agente de usuario (navegador).
  4. Dado que los navegadores son confiables implícitamente (la idea de un agente de usuario es actuar en nombre del usuario), pueden ayudar a mejorar esta situación.
  5. La principal fuerza que frena el progreso aquí es el punto muerto de implementación . Las soluciones deben descomponerse en pasos que brinden algún beneficio incremental por sí mismos.
  6. El método descentralizado más simple para express identidad que está integrado en la infraestructura de Internet es el nombre de dominio.
  7. Como segundo nivel de expresión de identidad, cada dominio maneja su propio conjunto de cuentas.
  8. El formulario “account @ domain” es conciso y está respaldado por una amplia gama de protocolos y esquemas de URI. Tal identificador es, por supuesto, más universalmente reconocido como una dirección de correo electrónico.
  9. Los proveedores de correo electrónico ya son los principales proveedores de identidad de facto en línea. Los flujos de restablecimiento de contraseña actuales generalmente le permiten tomar el control de una cuenta si puede probar que controla la dirección de correo electrónico asociada de esa cuenta.
  10. El protocolo de correo electrónico verificado fue propuesto para proporcionar un método seguro, basado en criptografía de clave pública, para simplificar el proceso de probar al dominio B que tiene una cuenta en el dominio A.
  11. Para los navegadores que no son compatibles con el Protocolo de correo electrónico verificado (actualmente todos ellos), Mozilla proporciona un complemento que implementa el protocolo en el código JavaScript del lado del cliente.
  12. For email services that don’t support the Verified Email Protocol, the protocol allows third parties to act as a trusted intermediary, asserting that they’ve verified a user’s ownership of an account. It is not desirable to have a large number of such third parties; this capability is intended only to allow an upgrade path, and it is much preferred that email services provide these assertions themselves.
  13. Mozilla offers their own service to act as such a trusted third party. Service Providers (that is, Relying Parties) implementing the Verified Email Protocol may choose to trust Mozilla’s assertions or not. Mozilla’s service verifies users’ account ownership using the conventional means of sending an email with a confirmation link.
  14. Service Providers may, of course, offer this protocol as an option in addition to any other method(s) of authentication they might wish to offer.
  15. A big user interface benefit being sought here is the “identity selector”. When a user visits a site and chooses to authenticate, their browser shows them a selection of email addresses (“personal”, “work”, “political activism”, etc.) they may use to identify themselves to the site.
  16. Another big user interface benefit being sought as part of this effort is helping the browser know more about the user’s session – who they’re signed in as currently, primarily – so it may display that in the browser chrome.
  17. Because of the distributed nature of this system, it avoids lock-in to major sites like Facebook, Twitter, Google, etc. Any individual can own their own domain and therefore act as their own identity provider.

This is not strictly “form-based authentication for websites”. But it is an effort to transition from the current norm of form-based authentication to something more secure: browser-supported authentication.

I just thought I’d share this solution that I found to be working just fine.

I call it the Dummy Field (though I haven’t invented this so don’t credit me).

In short: you just have to insert this into your

and check for it to be empty at when validating:

  

The trick is to fool a bot into thinking it has to insert data into a required field, that’s why I named the input “email”. If you already have a field called email that you’re using you should try naming the dummy field something else like “company”, “phone” or “emailaddress”. Just pick something you know you don’t need and what sounds like something people would normally find logical to fill in into a web form. Now hide the input field using CSS or JavaScript/jQuery – whatever fits you best – just don’t set the input type to hidden or else the bot won’t fall for it.

When you are validating the form (either client or server side) check if your dummy field has been filled to determine if it was send by a human or a bot.

Ejemplo:

In case of a human: The user will not see the dummy field (in my case named “email”) and will not attempt to fill it. So the value of the dummy field should still be empty when the form has been send.

In case of a bot: The bot will see a field whose type is text and a name email (or whatever it is you called it) and will logically attempt to fill it with appropriate data. It doesn’t care if you styled the input form with some fancy CSS, web-developers do it all the time. Whatever the value in the dummy field is, we don’t care as long as it’s larger than 0 characters.

I used this method on a guestbook in combination with CAPTCHA , and I haven’t seen a single spam post since. I had used a CAPTCHA-only solution before, but eventually it resulted in about five spam posts every hour. Adding the dummy field in the form has stopped (at least till now) all the spam from appearing.

I believe this can also be used just fine with a login/authentication form.

Warning : Of course this method is not 100% fool proof. Bots can be programmed to ignore input fields with the style display:none applied to it. You also have to think about people who use some form of auto-completion (like most browsers have built-in!) to auto-fill all form fields for them. They might just as well pick up a dummy field.

You can also vary this up a little by leaving the dummy field visible but outside the boundaries of screen, but this is totally up to you.

¡Ser creativo!

I do not think the above answer is “wrong” but there are large areas of authentication that are not touched upon (or rather the emphasis is on “how to implement cookie sessions”, not on “what options are available and what are the trade offs”.

My suggested edits / answers are

  • The problem lies more in account setup than in password checking.
  • The use of two factor authenitication is much more secure than more clever means of password encryption
  • Do NOT try to implement your own login form or database storage of passwords, unless the data being stored is valueless at account creation and self-generated (that is, web 2.0 style like Facebook, Flickr , etc.)

    1. Digest Authentication is a standards based approach supported in all major browsers and servers, that will not send a password even over a secure channel.

This avoids any need to have “sessions” or cookies as the browser itself will re-encrypt the communication each time. It is the most “lightweight” development approach.

However, I do not recommend this, except for public, low value services. This is an issue with some of the other answers above – do not try an re-implement server-side authetication mechanisms – this problem has been solved and is supported by most major browsers. Do not use cookies. Do not store anything in your own hand-rolled database. Just ask, per request, if the request is autheticated. Everything else should be supported by configuration and third-party trusted software.

Asi que …

First, we are confusing the initial creation of an account (with a password) with the re-checking of the password subsequently. If I am Flickr and creating your site for the first time, the new user has access to zero value (blank web space). I truly do not care if the person creating the account is lying about their name. If I am creating an account of the hospital intranet / extranet, the value lies in all the medical records, and so I do care about the identity (*) of the account creator.

This is the very very hard part. The only decent solution is a web of trust. For example, you join the hospital as a doctor. You create a web page hosted somewhere with your photo, your passport number and a public key, and hash them all with the private key. You then visit the hospital and the system administrator looks at your passport, sees if the photo matches you, and then hashes the web page / photo hash with the hospital private key. From now on we can securely exchange keys and tokens. As can anyone who trusts the hospital (there is the secret sauce BTW). The system administrator can also give you an RSA dongle or other two-factor authentication.

But this is a lot of hassle, and not very web 2.0. However, it is the only secure way to create new accounts that have access to valuable information that is not self-created.

  1. Kerberos and SPNEGO – single sign on mechanisms with a trusted third party – basically the user verifies against a trusted third party. (NB this is not in any way the not to be trusted OAuth )

  2. SRP – sort of clever password authentication without a trusted third party. But here we are getting into the realms of “it’s safer to use two factor authentication, even if that’s costlier”

  3. SSL client side – give the clients a public key certificate (support in all major browsers – but raises questions over client machine security).

In the end it’s a tradeoff – what is the cost of a security breach vs the cost of implementing more secure approaches. One day, we may see a proper PKI widely accepted and so no more own rolled authentication forms and databases. One day…

When hashing, don’t use fast hash algorithms such as MD5 (many hardware implementations exist). Use something like SHA-512. For passwords, slower hashes are better.

The faster you can create hashes, the faster any brute force checker can work. Slower hashes will therefore slow down brute forcing. A slow hash algorithm will make brute forcing impractical for longer passwords (8 digits +)

A good article about realistic password strength estimation is:

Dropbox Tech Blog » Blog Archive » zxcvbn: realistic password strength estimation

My favourite rule in regards to authentication systems: use passphrases, not passwords. Easy to remember, hard to crack. More info: Coding Horror: Passwords vs. Pass Phrases

I’d like to add one suggestion I’ve used, based on defense in depth. You don’t need to have the same auth&auth system for admins as regular users. You can have a separate login form on a separate url executing separate code for requests that will grant high privileges. This one can make choices that would be a total pain to regular users. One such that I’ve used is to actually scramble the login URL for admin access and email the admin the new URL. Stops any brute force attack right away as your new URL can be arbitrarily difficult (very long random string) but your admin user’s only inconvenience is following a link in their email. The attacker no longer knows where to even POST to.

I dont’t know whether it was best to answer this as an answer or as a comment. I opted for the first option.

Regarding the poing PART IV: Forgotten Password Functionality in the first answer, I would make a point about Timing Attacks.

In the Remember your password forms, an attacker could potentially check a full list of emails and detect which are registered to the system (see link below).

Regarding the Forgotten Password Form, I would add that it is a good idea to equal times between successful and unsucessful queries with some delay function.

https://crypto.stanford.edu/~dabo/papers/webtiming.pdf

I would like to add one very-important comment:

  • “In a corporate, intra- net setting,” most if not all of the foregoing might not apply!

Many corporations deploy “internal use only” websites which are, effectively, “corporate applications” that happen to have been implemented through URLs. These URLs can (supposedly …) only be resolved within “the company’s internal network.” (Which network magically includes all VPN-connected ‘road warriors.’)

When a user is dutifully-connected to the aforesaid network, their identity (“authentication”) is [already …] “conclusively known,” as is their permission (“authorization”) to do certain things … such as … “to access this website.”

This “authentication + authorization” service can be provided by several different technologies, such as LDAP (Microsoft OpenDirectory) , or Kerberos.

From your point-of-view, you simply know this: that anyone who legitimately winds-up at your website must be accompanied by [an environment-variable magically containing …] a “token.” ( ie The absence of such a token must be immediate grounds for 404 Not Found .)

The token’s value makes no sense to you, but, should the need arise, “appropriate means exist” by which your web-site can “[authoritatively] ask someone who knows (LDAP… etc.)” about any and every(!) question that you may have. In other words, you do not avail yourself of any “home-grown logic.” Instead, you inquire of The Authority and implicitly trust its verdict.

Uh huh … it’s quite a mental-switch from the “wild-and-wooly Internet.”

Use OpenID Connect or User-Managed Access .

As nothing is more efficient than not doing it at all.