PARTE I: Cómo iniciar sesión
Asumiremos que ya sabe cómo crear un formulario HTML de inicio de sesión + contraseña que PUBLICA los valores en un script en el lado del servidor para la autenticación. Las secciones a continuación tratarán los patrones para una autenticación práctica y sólida, y cómo evitar las trampas de seguridad más comunes.
¿A HTTPS o no a HTTPS?
A menos que la conexión ya sea segura (es decir, tunelizada a través de HTTPS usando SSL / TLS), los valores de su formulario de inicio de sesión se enviarán en texto sin formato, lo que permite que cualquier persona que escuche la línea entre el navegador y el servidor web pueda leer los inicios de sesión a medida que pasan mediante. Este tipo de escuchas telefónicas se realiza de forma rutinaria por los gobiernos, pero en general, no abordaremos los cables 'propios' más que para decir esto: solo use HTTPS.
En esencia, la única forma práctica de protegerse contra escuchas telefónicas / rastreo de paquetes durante el inicio de sesión es mediante HTTPS u otro esquema de cifrado basado en certificados (por ejemplo, TLS ) o un esquema comprobado y probado de desafío-respuesta (por ejemplo, el Diffie-Hellman basado en SRP). Cualquier otro método puede ser burlado fácilmente por un atacante que escuche a escondidas.
Por supuesto, si está dispuesto a ser un poco poco práctico, también puede 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) Roll-your-own JavaScript cifrado / hashing
Dado el costo percibido (aunque ahora evitable ) y la dificultad técnica de configurar un certificado SSL en su sitio web, algunos desarrolladores se ven tentados a implementar sus propios esquemas de cifrado o hash en el navegador para evitar pasar inicios de sesión de texto sin cifrar por un cable no seguro.
Si bien este es un pensamiento noble, es esencialmente inútil (y puede ser una falla de seguridad ) a menos que se combine con uno de los anteriores, es decir, asegurar la línea con un cifrado fuerte o usar una respuesta de desafío probada 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 el hash de la contraseña puede ser efectivo contra la divulgación de la contraseña , 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ás entregando al atacante nombre de usuario, sal y contraseña hash).
CAPTCHAS contra la humanidad
CAPTCHA está destinado a frustrar una categoría específica de ataque: diccionario automatizado / prueba y error de fuerza bruta sin operador humano. No hay duda de que esta es una amenaza real, sin embargo, hay formas de tratarlo sin problemas que no requieren un CAPTCHA, específicamente esquemas de aceleración de inicio de sesión del lado del servidor específicamente diseñados; discutiremos eso más adelante.
Sepa que las implementaciones de CAPTCHA no se crean por igual; a menudo no tienen solución humana, la mayoría de ellos no son efectivos 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 500 pruebas), y algunas implementaciones pueden ser técnicamente ilegal en algunos países (ver la hoja de trucos de autenticación OWASP ). Si debe usar un CAPTCHA, use el reCAPTCHA de Google , ya que es difícil de OCR por definición (ya que usa escaneos de libros ya mal clasificados por OCR) y se esfuerza mucho por ser fácil de usar.
Personalmente, tiendo a encontrar CAPTCHAS molesto, y los uso solo como último recurso cuando un usuario no ha podido iniciar sesión varias veces y los retrasos de aceleración se han agotado. Esto ocurrirá raramente lo suficiente como para ser aceptable, y fortalece el sistema en su conjunto.
Almacenamiento de contraseñas / verificación de inicios de sesión
Finalmente, esto puede ser de conocimiento común después de todos los hacks muy publicitados y las filtraciones de datos de usuarios que hemos visto en los últimos años, pero hay que decir: No almacene contraseñas en texto sin cifrar en su base de datos. Las bases de datos de los usuarios se piratean, filtran o recogen de forma rutinaria mediante inyección SQL, y si está almacenando contraseñas sin formato, de texto sin formato, se acabó el juego instantáneamente 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 hashing usando una función de derivación de clave . Cada vez que se crea un nuevo usuario o se cambia una contraseña, toma la contraseña y la ejecuta a través de un KDF, como Argon2, bcrypt, scrypt o PBKDF2, convirtiendo la contraseña de texto sin formato ("correcthorsebatterystaple") en una cadena larga 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 pasando la sal y compara la cadena hash resultante con el valor almacenado en su base de datos. Argon2, bcrypt y scrypt ya almacenan la sal con el hash. Consulte este artículo en sec.stackexchange para obtener información más detallada.
La razón por la que se usa una sal es que el hash en sí mismo no es suficiente: querrás agregar una llamada 'sal' para proteger el hash contra las tablas del arco iris . Una sal efectivamente evita que dos contraseñas que coinciden exactamente se almacenen como el mismo valor hash, evitando que se escanee toda la base de datos en una ejecución si un atacante está ejecutando un ataque de adivinación de contraseña.
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 seguras (es decir, generalmente no contienen suficiente entropía) y un atacante con acceso a los hash podría completar un ataque de adivinación de contraseñas en un tiempo relativamente corto. Esta es la razón por la que se usan KDF: estos efectivamente "estiran la clave" , lo que significa que cada contraseña que adivina un atacante provoca múltiples repeticiones del algoritmo hash, por ejemplo, 10,000 veces, lo que hace que el atacante adivine la contraseña 10,000 veces más lento.
Datos de la 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 usuario y ha encontrado una coincidencia, el sistema necesita una forma de recordar que el navegador ha sido autenticado. Este hecho solo debe almacenarse del lado del servidor en los datos de la sesión.
Si no está familiarizado con los datos de la sesión, así es como funciona: una sola cadena generada aleatoriamente se almacena en una cookie que caduca y se usa para hacer referencia a una colección de datos, los datos de la sesión, que se almacenan en el servidor. Si está utilizando un marco MVC, esto ya se maneja indudablemente.
Si es posible, asegúrese de que la cookie de sesión tenga los indicadores seguros y HTTP Only establecidos cuando se envían al navegador. El indicador HttpOnly proporciona cierta protección contra la cookie que se lee a través del ataque XSS. El indicador seguro garantiza que la cookie solo se envíe de vuelta a través de HTTPS y, por lo tanto, protege contra ataques de detección de redes. El valor de la cookie no debe ser predecible. Cuando se presenta 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 casilla de verificación "Recordarme" infame
Las cookies de inicio de sesión persistentes (funcionalidad "recordarme") son una zona peligrosa; por un lado, son 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 usarlos en computadoras públicas y olvidarse de cerrar 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 regularmente, pero sé cómo manejarlos de manera segura. Si está seguro de que sus usuarios saben lo mismo, puede usar inicios de sesión persistentes con la conciencia limpia. Si no, bueno, entonces puedes suscribirte a la filosofía de que los usuarios que son descuidados con sus credenciales de inicio de sesión se lo imponen si son pirateados. No es como si fuéramos a las casas de nuestros usuarios y arrancamos todas esas notas Post-It que inducen el uso de la palma de la mano con las contraseñas que han alineado en el borde de sus monitores.
Por supuesto, algunos sistemas no pueden permitirse tener ningún cuentas hackeadas; para tales sistemas, no hay forma de justificar tener inicios de sesión persistentes.
Si decides implementar cookies de inicio de sesión persistentes, así es como lo haces:
Primero, tómese un tiempo para leer el artículo de Paragon Initiative sobre el tema. Tendrá que acertar un montón de elementos, y el artículo hace un gran trabajo al explicar cada uno.
Y solo para reiterar uno de los escollos más comunes, ¡NO ALMACENE LA COOKIE DE INICIO DE SESIÓN PERSONAL (TOKEN) EN SU BASE DE DATOS, ¡SOLO UN CHOQUE! El token de inicio de sesión es Equivalente a la contraseña, por lo que si un atacante tiene en sus manos su base de datos, podría usar los tokens para iniciar sesión en cualquier cuenta, como si fueran combinaciones de texto libre de inicio de sesión y contraseña. Por lo tanto, use hashing (de acuerdo con https://security.stackexchange.com/a/63438/5002, un hash débil funcionará bien para este propósito) al almacenar tokens de inicio de sesión persistentes.
PARTE III: Uso de preguntas secretas
No implemente 'preguntas secretas' . La función 'preguntas secretas' es un antipatrón de seguridad. Lea el documento del enlace número 4 de la lista DEBE LEER. Puedes preguntarle a Sarah Palin sobre eso, después de que 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 de la madre o su mascota favorita
Una simple 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. Lo cual, para cualquier contraseña decente, es cada pregunta que puedas imaginar
En conclusión, las preguntas de seguridad son inherentemente inseguras en prácticamente todas sus formas y variaciones, y no deben emplearse en un esquema de autenticación por ningún motivo.
La verdadera razón por la que las preguntas de seguridad incluso existen en la naturaleza es que ahorran convenientemente el costo de algunas 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 debe usar preguntas de seguridad para manejar contraseñas de usuario olvidadas / perdidas; Tampoco hace falta decir que nunca debe enviar por correo electrónico a los usuarios sus contraseñas reales. Hay al menos dos escollos más comunes para evitar en este campo:
No restablezca una contraseña olvidada a una contraseña segura generada automáticamente; tales contraseñas son notoriamente difíciles de recordar, lo que significa que el usuario debe cambiarla o escribirla, por ejemplo, en un Post-It amarillo brillante 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 escribirlas).
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 modificado 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 sin formato a la dirección de correo electrónico del usuario, luego escríbalo, 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 propio formulario de inicio de sesión, o un atacante simplemente usará esto para obtener acceso. Es un buen comienzo asegurarse de generar 'códigos de contraseña perdidos' muy largos (por ejemplo, 16 caracteres alfanuméricos que distinguen entre mayúsculas y minúsculas), pero considere agregar el mismo esquema de aceleración que hace para el formulario de inicio de sesión.
PARTE V: Verificar la seguridad 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
De acuerdo, puede que la lista no es la canónica lista de la mayoría de las contraseñas comunes en cualquier sistema en cualquier lugar siempre , pero es una buena indicación de cómo la gente pobre va a elegir sus contraseñas cuando no existe una política forzada en su lugar. Además, la lista se ve terriblemente cerca de casa cuando la compara con análisis disponibles públicamente de contraseñas recientemente robadas.
Entonces: sin requisitos mínimos de seguridad de contraseña, el 2% de los usuarios usa una de las 20 contraseñas más comunes. Significado: si un atacante obtiene solo 20 intentos, 1 de cada 50 cuentas en su sitio web será descifrable.
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 diccionario y un análisis de diseño del 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 seguridad de la contraseña y mostrar un medidor de fuerza visual a un usuario es bueno, pero insuficiente. A menos que se aplique, 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 la seguridad de la contraseña xkcd de Randall Munroe .
Utilice la API Have I Been Pwned de Troy Hunt para verificar las contraseñas de los usuarios contra las contraseñas comprometidas en violaciones de datos públicos.
PARTE VI: Mucho más, o: Prevención de intentos de inicio de sesión rápido
Primero, eche un vistazo a los números: Velocidades de recuperación de contraseña: ¿cuánto tiempo durará su contraseña?
Si no tiene tiempo para revisar las tablas en ese enlace, aquí está la lista de ellas:
Prácticamente no lleva tiempo descifrar una contraseña débil, incluso si la está descifrando con un ábaco
Prácticamente no lleva tiempo descifrar una contraseña alfanumérica de 9 caracteres si no distingue entre mayúsculas y minúsculas
Prácticamente no lleva tiempo descifrar una intrincada contraseña de mayúsculas y minúsculas, símbolos y letras y números, si tiene menos de 8 caracteres de longitud (una PC de escritorio puede buscar en todo el espacio de teclas de hasta 7 caracteres en una cuestión de días o incluso horas)
Sin embargo, tomaría una cantidad excesiva de tiempo descifrar incluso una contraseña de 6 caracteres, si estuviera limitado a un intento por segundo.
Entonces, ¿qué podemos aprender de estos números? Bueno, mucho, pero podemos centrarnos en la parte más importante: el hecho de que evitar grandes cantidades de intentos de inicio de sesión sucesivos de fuego rápido (es decir, el ataque de fuerza bruta ) realmente no es tan difícil. Pero prevenirlo bien 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 como ya está empleando una política de contraseñas segura, no deberían ser un problema) :
Presente un CAPTCHA después de N intentos fallidos (molesto como el infierno y, a menudo, ineficaz, pero me estoy repitiendo aquí)
Bloqueo de cuentas y solicitud de verificación de correo electrónico después de N intentos fallidos (este es un ataque DoS a punto de ocurrir)
Y finalmente, aceleración de inicio de sesión : es decir, establecer un retraso de tiempo entre intentos después de N intentos fallidos (sí, los ataques DoS todavía son posibles, pero al menos son mucho menos probables y mucho más complicados de lograr).
Mejor práctica n. ° 1: un retraso de tiempo corto que aumenta con el número de intentos fallidos, como:
- 1 intento fallido = sin demora
- 2 intentos fallidos = 2 segundos de retraso
- 3 intentos fallidos = 4 segundos de retraso
- 4 intentos fallidos = retraso de 8 segundos
- 5 intentos fallidos = 16 segundos de retraso
- etc.
El ataque DoS a este esquema sería muy poco práctico, ya que el tiempo de bloqueo resultante es ligeramente mayor que la suma de los tiempos de bloqueo anteriores.
Para aclarar: El retraso 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 intentos de inicio de sesión en una cuenta específica o desde una dirección IP específica no serán aceptados o 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 retraso.
Mejor práctica # 2: un retraso de tiempo medio que entra en vigencia después de N intentos fallidos, como:
- 1-4 intentos fallidos = sin demora
- 5 intentos fallidos = 15-30 min de retraso
El ataque DoS a este esquema sería poco práctico, pero ciertamente factible. Además, puede ser relevante tener en cuenta que un retraso tan largo puede ser muy molesto para un usuario legítimo. A los usuarios olvidadizos no les gustará.
Mejor práctica # 3: Combinando los dos enfoques, ya sea un retraso fijo de corto tiempo que entra en vigencia después de N intentos fallidos, como:
- 1-4 intentos fallidos = sin demora
- Más de 5 intentos fallidos = 20 segundos de retraso
O, un retraso creciente con un límite superior fijo, como:
- 1 intento fallido = 5 segundos de retraso
- 2 intentos fallidos = 15 segundos de retraso
- 3+ intentos 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 debe considerarse como la mejor práctica, incluso si es ciertamente del lado restrictivo.
Sin embargo, como regla general, diría: cuanto más fuerte sea su política de contraseña, menos tendrá que molestar a los usuarios con demoras. Si necesita contraseñas seguras (alfanuméricas que distingan entre mayúsculas y minúsculas + números y símbolos requeridos) de más de 9 caracteres, puede dar a los usuarios 2-4 intentos de contraseña sin demora antes de activar la limitación.
El ataque DoS a este esquema de aceleración de inicio de sesión final sería muy poco práctico. Y como toque final, siempre permita que pasen inicios de sesión persistentes (cookies) (y / o un formulario de inicio de sesión verificado por CAPTCHA) para que los usuarios legítimos ni siquiera se retrasen mientras el ataque está en curso . De esa manera, el ataque DoS muy poco práctico 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
Como comentario aparte, los atacantes más avanzados tratarán de eludir la limitación de inicio de sesión 'extendiendo sus actividades':
Distribuir los intentos en una botnet para evitar el marcado de direcciones IP
En lugar de elegir un usuario y probar las 50,000 contraseñas más comunes (que no pueden, debido a nuestra limitación), elegirán LA contraseña más común y la probarán contra 50,000 usuarios. De esa manera, no solo evitan medidas de intentos máximos como CAPTCHA y aceleración de inicio de sesión, sino que también aumentan sus posibilidades de éxito, ya que la contraseña más común número 1 es mucho más probable que el número 49.995
Espaciar las solicitudes de inicio de sesión para cada cuenta de usuario, digamos, con 30 segundos de diferencia, para escabullirse bajo el radar
Aquí, la mejor práctica sería registrar el número de inicios de sesión fallidos, en todo el sistema , y usar un promedio continuo de la frecuencia de inicio de sesión incorrecto de su sitio como base para un límite superior que luego impone a todos los usuarios.
Demasiado abstracto? Déjame reformular:
Digamos 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 a 3 veces eso, es decir. 360 intentos fallidos durante un período de 24 horas. Luego, si el número total de intentos fallidos en todas las cuentas excede ese número dentro de un día (o incluso mejor, controle la tasa de aceleración y se dispare en un umbral calculado), se activa la limitación de inicio de sesión en todo el sistema, lo que significa retrasos breves para TODOS los usuarios (aún, con la excepción de inicios de sesión de cookies y / o inicios de sesión de CAPTCHA de respaldo).
También publiqué una pregunta con más detalles y una muy buena discusión sobre cómo evitar trampas difíciles para 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 escritas y perdidas, computadoras portátiles con claves robadas o usuarios que ingresan a los sitios de phishing. Los inicios de sesión pueden protegerse aún más con la autenticación de dos factores, que utiliza factores fuera de banda como los 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 completamente a un servicio de inicio de sesión único, donde otro proveedor maneja la recopilación de credenciales. Esto empuja el problema a un tercero de confianza. Google y Twitter proporcionan servicios SSO basados en estándares, mientras que Facebook ofrece una solución propietaria similar.
ENLACES DEBEN LEER Acerca de la autenticación web
- Guía de autenticación OWASP / Hoja de referencia de autenticación OWASP
- Lo que se debe y no se debe hacer con la autenticación del cliente en la Web (documento de investigación del MIT muy legible)
- Wikipedia: cookie HTTP
- 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)