¿Cuál es la mejor contramedida de fuerza bruta distribuida?


151

Primero, un poco de historia: no es ningún secreto que estoy implementando un sistema auth + auth para CodeIgniter, y hasta ahora estoy ganando (por así decirlo). Pero me he encontrado con un desafío bastante trivial (uno que la mayoría de las bibliotecas de autenticación omiten por completo, pero insisto en manejarlo correctamente): cómo lidiar de manera inteligente con ataques de fuerza bruta de nombre de usuario variable, distribuidos y a gran escala .

Conozco todos los trucos habituales:

  1. Limitar el número de intentos fallidos por IP / host y negar el acceso a los infractores (por ejemplo, Fail2Ban), lo que ya no funciona ya que las botnets se han vuelto más inteligentes
  2. Combinando lo anterior con una lista negra de IP / hosts conocidos 'malos' (por ejemplo, DenyHosts), que se basa en que las botnets caen en el n. ° 1, que cada vez más no hacen.
  3. Listas blancas de IP / host combinadas con autenticación tradicional (lamentablemente inútil con usuarios dinámicos de IP y la gran rotación en la mayoría de los sitios web)
  4. Establecer un límite en todo el sitio para el número de intentos fallidos dentro de un período de N minutos / hora, y estrangular (suspender) todos los intentos de inicio de sesión después de eso durante varios minutos / horas (con el problema de que DoS atacarte se convierte en un juego de niños de botnet)
  5. Firmas digitales obligatorias (certificados de clave pública) o tokens de hardware RSA para todos los usuarios sin opción de inicio de sesión / contraseña (sin duda, una solución sólida, pero solo práctica para servicios cerrados y dedicados)
  6. Forzadas esquemas de contraseñas ultra-fuertes (por ejemplo,> 25 caracteres sin sentido con símbolos - de nuevo, demasiado poco práctico para los usuarios ocasionales)
  7. Y finalmente, CAPTCHA (que podría funcionar en la mayoría de los casos, pero es molesto para los usuarios y prácticamente inútil contra un atacante resuelto e ingenioso )

Ahora, estas son solo las ideas teóricamente viables. Hay muchas ideas basura que abren el sitio (por ejemplo, a ataques DoS triviales). Lo que quiero es algo mejor. Y por mejor, quiero decir:

  • Tiene que ser seguro (+) contra ataques DoS y de fuerza bruta, y no introducir nuevas vulnerabilidades que puedan permitir que un bot ligeramente más astuto continúe operando bajo el radar.

  • Tiene que ser automatizado. Si requiere que un operador humano verifique cada inicio de sesión o monitoree actividades sospechosas, no funcionará en un escenario del mundo real

  • Tiene que ser factible para el uso principal de la web (es decir, alta rotación, alto volumen y registro abierto que pueden realizar personas que no sean programadores)

  • No puede impedir la experiencia del usuario hasta el punto en que los usuarios ocasionales se molesten o se sientan frustrados (y potencialmente abandonen el sitio)

  • No puede involucrar gatitos, a menos que sean realmente gatitos seguros

(+) Por 'seguro', quiero decir al menos tan seguro como la capacidad de un usuario paranoico de mantener su contraseña en secreto

Entonces, ¡vamos a escucharlo! Como lo harias ¿Conoces una práctica recomendada que no he mencionado (por favor, di que sí)? Admito que tengo una idea propia (combinando ideas de 3 y 4), pero dejaré que los verdaderos expertos hablen antes de avergonzarme ;-)

Respuestas:


68

Muy bien, suficiente retraso; esto es lo que se me ocurrió hasta ahora

(perdón, larga publicación por delante. Sé valiente, amigo, el viaje valdrá la pena)

Combinando los métodos 3 y 4 de la publicación original en una especie de lista blanca 'difusa' o dinámica, y luego, y aquí está el truco, no bloquear las IP no incluidas en la lista blanca, simplemente estrangularlas al infierno y viceversa .

Tenga en cuenta que esta medida solo pretende frustrar este tipo de ataque muy específico. En la práctica, por supuesto, funcionaría en combinación con otros enfoques de mejores prácticas para la autenticación: limitación de nombre de usuario fijo, limitación por IP, política de contraseña segura con código, inicio de sesión de cookie sin estrangulamiento, hash todos los equivalentes de contraseña antes de guardarlos, nunca utilizando preguntas de seguridad, etc.

Suposiciones sobre el escenario de ataque

Si un atacante apunta a nombres de usuario variables, nuestra limitación de nombre de usuario no se activa. Si el atacante está usando una botnet o tiene acceso a un amplio rango de IP, nuestra limitación de IP es impotente. Si el atacante ha eliminado previamente nuestra lista de usuarios (generalmente posible en servicios web de registro abierto), no podemos detectar un ataque continuo en función de la cantidad de errores de "usuario no encontrado". Y si aplicamos una restricción restrictiva en todo el sistema (todos los nombres de usuario, todas las IP), cualquier ataque de este tipo afectará a todo nuestro sitio durante la duración del ataque más el período de limitación.

Entonces necesitamos hacer algo más.

La primera parte de la contramedida: lista blanca

De lo que podemos estar bastante seguros es que el atacante no puede detectar y falsificar dinámicamente las direcciones IP de varios miles de nuestros usuarios (+). Lo que hace factible la lista blanca . En otras palabras: para cada usuario, almacenamos una lista de las IP (hash) desde donde el usuario ha iniciado sesión (recientemente) previamente.

Por lo tanto, nuestro esquema de listas blancas funcionará como una 'puerta principal' bloqueada, donde un usuario debe estar conectado desde una de sus IP 'buenas' reconocidas para poder iniciar sesión. Un ataque de fuerza bruta en esta 'puerta principal' sería prácticamente imposible (+).

(+) a menos que el atacante 'posea' el servidor, todos los cuadros de nuestros usuarios o la conexión en sí misma, y ​​en esos casos, ya no tenemos un problema de 'autenticación', tenemos un verdadero pull-the de tamaño de franquicia -enchufe la situación FUBAR

La segunda parte de la contramedida: aceleración de IP no reconocidas en todo el sistema

Para que una lista blanca funcione para un servicio web de registro abierto, donde los usuarios cambian de computadora con frecuencia y / o se conectan desde direcciones IP dinámicas, necesitamos mantener abierta una 'puerta de acceso' para los usuarios que se conectan desde IP no reconocidas. El truco es diseñar esa puerta para que las botnets se atasquen y los usuarios legítimos se molesten lo menos posible .

En mi esquema, esto se logra al establecer un número máximo muy restrictivo de intentos fallidos de inicio de sesión por IP no aprobadas durante, por ejemplo, un período de 3 horas (puede ser más prudente usar un período más corto o más largo según el tipo de servicio), y haciendo que esa restricción sea global , es decir. para todas las cuentas de usuario.

Incluso una fuerza bruta lenta (1-2 minutos entre intentos) se detectaría y frustraría de manera rápida y efectiva utilizando este método. Por supuesto, una fuerza bruta realmente lenta aún podría pasar desapercibida, pero velocidades demasiado lentas derrotan el propósito mismo del ataque de fuerza bruta.

Lo que espero lograr con este mecanismo de estrangulamiento es que si se alcanza el límite máximo, nuestra 'puerta de gato' se cierra por un tiempo, pero nuestra puerta principal permanece abierta para usuarios legítimos que se conectan por los medios habituales:

  • Ya sea conectándose desde una de sus IP reconocidas
  • O mediante el uso de una cookie de inicio de sesión persistente (desde cualquier lugar)

Los únicos usuarios legítimos que se verían afectados durante un ataque, es decir. mientras se activaba la limitación, serían los usuarios sin cookies de inicio de sesión persistentes que iniciaran sesión desde una ubicación desconocida o con una IP dinámica. Esos usuarios no podrán iniciar sesión hasta que la aceleración desaparezca (lo que podría llevar un tiempo si el atacante mantiene su botnet funcionando a pesar de la aceleración).

Para permitir que este pequeño subconjunto de usuarios se filtre a través de la puerta para gatos sellada de otro modo, incluso cuando los bots todavía la estaban golpeando, emplearía un formulario de inicio de sesión de 'respaldo' con un CAPTCHA. De modo que, cuando muestre el mensaje "Lo siento, pero no puede iniciar sesión desde esta dirección IP en este momento", incluya un enlace que diga " inicio de sesión seguro de respaldo - SOLO HUMANOS ( bots: no mentir ) ". Broma a un lado, cuando hacen clic en ese enlace, les dan un formulario de inicio de sesión autenticado reCAPTCHA que evita la limitación en todo el sitio. De esa manera, SI son humanos Y conocen el inicio de sesión + contraseña correctos (y son capaces de leer CAPTCHA), nunca se les negará el servicio, incluso si se conectan desde un host desconocido y no usan la cookie de inicio de sesión automático.

Ah, y solo para aclarar: dado que considero que los CAPTCHA son generalmente malos, la opción de inicio de sesión de 'copia de seguridad' solo aparecerá mientras la aceleración esté activa .

No se puede negar que un ataque sostenido como ese todavía constituiría una forma de ataque DoS, pero con el sistema descrito en su lugar, solo afectaría lo que sospecho que es un pequeño subconjunto de usuarios, es decir, personas que no usan el la cookie "recordarme" Y está iniciando sesión mientras ocurre un ataque Y no está iniciando sesión desde ninguna de sus IP habituales Y que no pueden leer CAPTCHA. Solo aquellos que pueden decir NO a TODOS esos criterios, específicamente los bots y las personas discapacitadas realmente desafortunadas , serán rechazados durante un ataque de bot.

EDITAR: En realidad, pensé en una forma de permitir que incluso los usuarios con problemas de CAPTCHA pasen durante un 'bloqueo': en lugar de, o como complemento del inicio de sesión de CAPTCHA de respaldo, proporcionar al usuario la opción de tener un solo uso , código de bloqueo específico del usuario enviado a su correo electrónico, que luego puede usar para evitar la limitación. Esto definitivamente cruza mi umbral de 'molestia', pero dado que solo se usa como último recurso para un pequeño subconjunto de usuarios, y dado que aún supera el bloqueo de su cuenta, sería aceptable.

(Además, tenga en cuenta que nada de esto sucede si el ataque es menos sofisticado que la desagradable versión distribuida que describí aquí. Si el ataque proviene de unas pocas IP o solo golpea algunos nombres de usuario, se frustrará mucho antes) y sin consecuencias para todo el sitio)


Entonces, esa es la contramedida que implementaré en mi biblioteca de autenticación, una vez que esté convencido de que es sólido y de que no hay una solución mucho más simple que me haya perdido. El hecho es que hay muchas maneras sutiles de hacer las cosas mal en seguridad, y no estoy por encima de hacer suposiciones falsas o lógicas irremediablemente defectuosas. Así que por favor, todos y cada uno de los comentarios, críticas y mejoras, sutilezas, etc. son muy apreciados.


1
¿Tal vez podría generar una contraseña 'especial' para cada usuario que podría usar si está en modo de bloqueo (y se conectan desde una nueva IP, etc.), esa contraseña especial es lo suficientemente complicada que no es posible aplicar la fuerza bruta?
Douglas Leeder

1
Eso podría funcionar, pero solo si los usuarios recuerdan esas contraseñas incluso si no las han usado antes (estos tipos de ataque no son comunes, y ningún botmaster que valga la pena se molestaría en mantener una en funcionamiento durante mucho tiempo después de ser estrangulada). El riesgo es demasiado grande que simplemente no podían recordar.
Jens Roland

1
Sin embargo, un método que definitivamente podría funcionar es proporcionar un enlace 'enviarme un código de bloqueo' a esos usuarios, permitiéndoles obtener un correo electrónico que contenga un token específico de usuario de un solo uso que les permita iniciar sesión, evitando el estrangulamiento
Jens Roland

1
@Abtin: Buena idea, excepto que sería 'entrar en la carrera armamentista', es decir. comenzar un 'quién puede burlar a quién' con las personas que crean listas de contraseñas para ataques de diccionario. Creo que una mejor manera sería la de hacer cumplir una política de contraseña segura por lo que no son ni contraseñas débiles
Jens Roland

1
@OrestisP .: Te estás perdiendo el punto del ataque distribuido: el número de intentos no válidos de cada IP es mínimo, por lo que el bloqueo por IP no puede funcionar. Además, la pregunta describe específicamente un ataque automático de fuerza bruta, por lo que 1) el atacante no es humano, sino más bien una botnet de máquinas zombies (que no pueden usar el inicio de sesión captcha); y 2) la naturaleza de la fuerza bruta del ataque requiere un número muy elevado de intentos de inicio de sesión para garantizar el éxito, lo que significa que no es factible resolver el captcha en una tienda de sudor en algún lugar (aunque sea posible si el atacante está bien financiado y determinado) suficiente).
Jens Roland

17

Unos simples pasos:

Incluya en la lista negra ciertos nombres de usuario comunes y úselos como un honeypot. Administrador, invitado, etc. No permita que nadie cree cuentas con estos nombres, por lo que si alguien intenta iniciar sesión, sabe que alguien está haciendo algo que no debería.

Asegúrese de que cualquier persona que tenga poder real en el sitio tenga una contraseña segura. Requerir que los administradores / moderadores tengan contraseñas más largas con una combinación de letras, números y símbolos. Rechace las contraseñas trivialmente simples de los usuarios habituales con una explicación.

Una de las cosas más simples que puede hacer es avisar a las personas cuando alguien intentó iniciar sesión en su cuenta y darles un enlace para informar el incidente si no fueron ellos. Un mensaje simple cuando inician sesión como "Alguien intentó iniciar sesión en su cuenta a las 4:20 AM del miércoles, bla, bla. Haga clic aquí si no fue usted". Te permite mantener algunas estadísticas sobre los ataques. Puede intensificar las medidas de monitoreo y seguridad si observa que hay un aumento repentino de accesos fraudulentos.


Buenos pensamientos Definitivamente estaba planeando implementar una política de contraseña automática que varía dinámicamente con el nivel de privilegio del usuario. La idea honeypot podría funcionar para algunos tipos de ataque, pero si el ataque se distribuye, el bloqueo de las IP que caen en su contra no será efectivo.
Jens Roland

Con respecto al 'Último intento de tiempo de inicio de sesión', esa es una buena estrategia para usuarios avanzados (que apuesto es por qué SO lo hace), pero tiene dos debilidades: (a) no aborda el problema de intrusión, solo informa que puede haber sucedido, y (b), la mayoría de los usuarios simplemente no recuerdan / no se preocupan
Jens Roland

1
Sí, el honeypot y los informes de usuarios son más sobre la recopilación de información. Pueden proporcionar algunas métricas valiosas para hacerle saber si / cuando ocurre un ataque lento de fuerza bruta.
patros

2
Para el honeypot, ¿no sería mejor tratar cualquier nombre de usuario inexistente como sospechoso que simplemente usar una lista fija de nombres de usuario malos conocidos? Desearía evitar bloquear a los usuarios que escribieron mal su nombre de usuario y no notaron el error al volver a intentar su contraseña varias veces, pero aún creo que hay formas en que podría ser valioso. Incluso podría evitar algunos "falsos positivos" construyendo un filtro de floración grande o una estructura de datos similar con variantes de nombres de usuario válidos, nombres, apellidos, nombres de correo electrónico, etc. a medida que se agregan usuarios.
R .. GitHub DEJA DE AYUDAR A ICE

11

Si entiendo el MO de los ataques de fuerza bruta correctamente, entonces uno o más nombres de usuario se prueban continuamente.

Hay dos sugerencias que no creo haber visto todavía aquí:

  • Siempre pensé que la práctica estándar era tener un breve retraso (aproximadamente un segundo) después de cada inicio de sesión incorrecto para cada usuario. Esto disuade la fuerza bruta, pero no sé cuánto tiempo un retraso de un segundo mantendría a raya un ataque de diccionario. (diccionario de 10,000 palabras == 10,000 segundos == aproximadamente 3 horas. Hmm. No es lo suficientemente bueno).
  • en lugar de una desaceleración en todo el sitio, por qué no un acelerador de nombre de usuario. El acelerador se vuelve cada vez más duro con cada intento incorrecto (hasta un límite, supongo que el usuario real aún puede iniciar sesión)

Editar : en respuesta a los comentarios sobre un acelerador de nombre de usuario: este es un acelerador específico de nombre de usuario sin tener en cuenta la fuente del ataque.

Si el nombre de usuario se estrangula, entonces se detectaría incluso un ataque de nombre de usuario coordinado (IP múltiple, conjetura simple por IP, mismo nombre de usuario). Los nombres de usuario individuales están protegidos por el acelerador, incluso si los atacantes son libres de probar otro usuario / pase durante el tiempo de espera.

Desde el punto de vista de los atacantes, durante el tiempo de espera puede ser capaz de adivinar por primera vez las 100 contraseñas y descubrir rápidamente una contraseña incorrecta por cuenta. Es posible que solo pueda realizar conjeturas de 50 segundos durante el mismo período de tiempo.

Desde el punto de vista de una cuenta de usuario, todavía se necesita el mismo número promedio de conjeturas para romper la contraseña, incluso si las conjeturas provienen de múltiples fuentes.

Para los atacantes, en el mejor de los casos, será el mismo esfuerzo romper 100 cuentas como lo haría con 1 cuenta, pero como no está acelerando en todo el sitio, puede acelerar el acelerador con bastante rapidez.

Refinamientos adicionales:

  • detectar IP que adivinan varias cuentas - 408 Tiempo de espera de solicitud
  • detectar IP que adivinan la misma cuenta: 408 Tiempo de espera de solicitud después de una gran cantidad (por ejemplo, 100) de conjeturas.

Ideas de IU (pueden no ser adecuadas en este contexto), que también pueden refinar lo anterior:

  • si tiene el control de la configuración de la contraseña, mostrarle al usuario qué tan segura es su contraseña lo alienta a elegir una mejor.
  • Si tiene el control de la página de inicio de sesión , después de un número pequeño (por ejemplo, 10) de conjeturas de un solo nombre de usuario, ofrezca un CAPTCHA.

Un acelerador de nombre de usuario más un acelerador de IP está bien contra ataques de nombre de usuario fijo o IP fijo, y hacen que los ataques tradicionales de diccionario no sean factibles. Pero si el atacante cambia constantemente los nombres de usuario, pasará sin activar un acelerador de nombre de usuario. Eso es lo que quiero contrarrestar
Jens Roland el

2
Gracias por la edición, James. Ahora estamos hablando. Me encanta la idea del 408. Sin embargo, incluso con una estricta limitación de nombre de usuario, una botnet que ataca a múltiples usuarios aún funcionaría. Y la comprobación de las 5000 principales contraseñas contra un usuario tiene menos probabilidades de tener éxito que la comprobación de la contraseña de la parte superior 1 de 5000 usuarios
Jens Roland

Nada como la paradoja del cumpleaños. En un grupo grande, muchos usarán contraseñas inseguras, y es probable que uno use cualquiera de las populares. También habrá un buen número de personas como yo que no serán atrapadas por tal ataque.
David Thornley

2
En realidad, es posible que tenga que volver a verificar las matemáticas en mi declaración anterior. Una vez que haya descartado las N contraseñas más comunes, la probabilidad de que el usuario tenga la contraseña # (N + 1) puede aumentar lo suficiente como para compensar la diferencia. Aunque la curva es probablemente lo suficientemente empinada para que ese no sea el caso
Jens Roland

9

Hay tres factores de autenticación:

  1. Un usuario sabe algo (es decir, una contraseña)
  2. Un usuario tiene algo (es decir, un llavero)
  3. Un usuario es algo (es decir, escaneo de retina)

Por lo general, los sitios web solo aplican la política n. ° 1. Incluso la mayoría de los bancos solo aplican la política 1. En su lugar, confían en un enfoque de "sabe algo más" para la autenticación de dos factores. (IE: un usuario conoce su contraseña y el apellido de soltera de su madre). Si puede, una forma de agregar un segundo factor de autenticación no es demasiado difícil.

Si puede generar alrededor de 256 caracteres de aleatoriedad, podría estructurarlo en una tabla de 16 × 16 y luego pedirle al usuario que le dé el valor en la tabla de la celda A-14, por ejemplo. Cuando un usuario se registre o cambie su contraseña, dele la tabla y dígale que la imprima y la guarde.

La dificultad con ese enfoque es que cuando un usuario olvida su contraseña, como lo hará, no puede simplemente ofrecer el estándar "responda esta pregunta e ingrese una nueva contraseña", ya que eso también es vulnerable a la fuerza bruta. Además, no puede restablecerlo y enviarles uno nuevo, ya que su correo electrónico también podría verse comprometido. (Ver: Makeuseof.com y su dominio robado).

Otra idea (que involucra gatitos), es lo que BOA llama SiteKey (creo que marcaron el nombre). Brevemente, el usuario debe cargar una imagen cuando se registra, y cuando intenta iniciar sesión, pídale que elija su imagen entre 8 o 15 (o más) al azar. Entonces, si un usuario carga una imagen de su gatito, teóricamente solo ellos saben exactamente qué imagen es suya de todos los otros gatitos (o flores o lo que sea). La única vulnerabilidad real que tiene este enfoque es el ataque del hombre en el medio.

Una idea más (sin embargo, sin gatitos) es rastrear las IP con las que los usuarios acceden al sistema y exigirles que realicen una autenticación adicional (captcha, elegir un gatito, elegir una clave de esta tabla) cuando inician sesión desde una dirección que no tienen No antes. Además, de forma similar a GMail, permite al usuario ver desde dónde ha iniciado sesión recientemente.

Editar, nueva idea:

Otra forma de validar los intentos de inicio de sesión es verificar si el usuario proviene o no de su página de inicio de sesión. No puede verificar los referentes, ya que pueden ser falsificados fácilmente. Lo que necesita es establecer una clave en la variable _SESSION cuando el usuario ve la página de inicio de sesión, y luego verificar para asegurarse de que existe la clave cuando envía su información de inicio de sesión. Si el bot no se envía desde la página de inicio de sesión, no podrá iniciar sesión. También puede facilitar esto al involucrar a JavaScript en el proceso, ya sea usándolo para configurar una cookie o agregando información al formulario después de que se haya cargado. O bien, puede dividir el formulario en dos envíos diferentes (es decir, el usuario ingresa su nombre de usuario, envía, luego en una nueva página ingresa su contraseña y vuelve a enviar).

La clave, en este caso, es el aspecto más importante. Un método común para generarlos es una combinación de los datos del usuario, su IP y el momento en que se enviaron.


Estoy seguro de que hay más, pero si la idea de SiteKey es exactamente lo que mencionó, un atacante no tiene que ser un MITM, solo puede ejecutar dos o tres intentos de inicio de sesión para ese usuario y elegir la imagen que se repite entre los aleatorios. Incluso si el conjunto de 8-15 imágenes es estático para el usuario X,
Jens Roland

(continuación) probablemente no sería demasiado difícil elegir la correcta, ya que las personas tienden a elegir tipos de imágenes predecibles (¡incluso imágenes de sus propios álbumes de Flickr!)
Jens Roland

2
Sí, pensé en el punto que mencionaste anoche después de que me fui a casa. Creo que la forma de solucionarlo es: cuando un usuario inicia sesión y proporciona una contraseña correcta, muestra su imagen y algunos otros números aleatorios. Cuando no proporcionen la contraseña correcta, muestre un número aleatorio
davethegr8

1
imágenes + 1, que pueden incluir o no su propia imagen. Además, tuve otra idea, ver la edición en la publicación. Pero sí, estas ideas son un poco difíciles / complicadas.
davethegr8

1
Eso "podría" funcionar, pero veo un par de problemas. ¿Qué sucede si el propietario de la foto elimina la imagen? ¿Cómo puede estar seguro de que las imágenes devueltas no serán ofensivas para su usuario? ¿Cómo recuerda un usuario dónde hizo clic? (Parece difícil de olvidar)
davethegr8

7

Anteriormente había respondido una pregunta muy similar en ¿Cómo puedo limitar los intentos de inicio de sesión de usuario en PHP ? Reitero la solución propuesta aquí, ya que creo que muchos de ustedes lo encontrarán informativo y útil para ver algún código real. Tenga en cuenta que el uso de un CAPTCHA podría no ser la mejor solución debido a los algoritmos cada vez más precisos que se utilizan en los destructores de CAPTCHA en la actualidad:

No puede simplemente evitar ataques DoS encadenando la aceleración a una sola IP o nombre de usuario. Demonios, ni siquiera puedes evitar los intentos de inicio de sesión de disparo rápido con este método.

¿Por qué? Porque el ataque puede abarcar múltiples direcciones IP y cuentas de usuario en aras de eludir sus intentos de estrangulamiento.

He visto en otros lugares que idealmente deberías rastrear todos los intentos fallidos de inicio de sesión en el sitio y asociarlos a una marca de tiempo, tal vez:

CREATE TABLE failed_logins(
    id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(16) NOT NULL,
    ip_address INT(11) UNSIGNED NOT NULL,
    attempted DATETIME NOT NULL
) engine=InnoDB charset=UTF8;

Decida ciertas demoras en función del número total de inicios de sesión fallidos en un período de tiempo determinado. Debe basar esto en datos estadísticos extraídos de su failed_loginstabla, ya que cambiarán con el tiempo según la cantidad de usuarios y cuántos de ellos pueden recordar (y escribir) su contraseña.


10 failed attempts = 1 second
20 failed attempts = 2 seconds
30 failed attempts = reCaptcha

Consulte la tabla en cada intento de inicio de sesión fallido para encontrar el número de inicios de sesión fallidos durante un período de tiempo determinado, digamos 15 minutos:


SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute);

Si el número de intentos durante el período de tiempo dado supera su límite, imponga la limitación u obligue a todos los usuarios a usar un captcha (es decir, reCaptcha) hasta que el número de intentos fallidos durante el período de tiempo determinado sea inferior al umbral.

// array of throttling
$throttle = array(10 => 1, 20 => 2, 30 => 'recaptcha');

// assume query result of $sql is stored in $row
$sql = 'SELECT MAX(attempted) AS attempted FROM failed_logins';
$latest_attempt = (int) date('U', strtotime($row['attempted']));
// get the number of failed attempts
$sql = 'SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute)';
// assume the number of failed attempts was stored in $failed_attempts
krsort($throttle);
foreach ($throttle as $attempts => $delay) {
    if ($failed_attempts > $attempts) {
        // we need to throttle based on delay
        if (is_numeric($delay)) {
            $remaining_delay = time() - $latest_attempt - $delay;
            // output remaining delay
            echo 'You must wait ' . $remaining_delay . ' seconds before your next login attempt';
        } else {
            // code to display recaptcha on login form goes here
        }
        break;
    }
}

El uso de reCaptcha en un cierto umbral garantizaría que se minimizara un ataque desde múltiples frentes y que los usuarios normales del sitio no experimentarían un retraso significativo por intentos de inicio de sesión fallidos legítimos. No puedo garantizar la prevención, ya que ya se ha ampliado para que los CAPTCHA puedan ser eliminados. Existen soluciones alternativas, quizás una variante de "Nombra a este animal", que podría funcionar bastante bien como un sustituto.


6

Tengo que preguntar si ha realizado un análisis de costo-beneficio de este problema; Parece que está tratando de protegerse de un atacante que tiene suficiente presencia en la web para adivinar varias contraseñas, enviando quizás 3-5 solicitudes por IP (ya que ha rechazado la limitación de IP). ¿Cuánto (aproximadamente) costaría ese tipo de ataque? ¿Es más costoso que el valor de las cuentas que está tratando de proteger? ¿Cuántas botnets gigantes quieren lo que tienes?

La respuesta podría ser no, pero si lo es, espero que obtenga ayuda de un profesional de seguridad de algún tipo; la habilidad de programación (y el puntaje de StackOverflow) no se correlacionan fuertemente con los conocimientos de seguridad.


(Quiere decir si la respuesta es 'no', es decir, que el costo de un ataque de botnet NO es demasiado alto en relación con las cuentas)
Jens Roland

Pero de todos modos, traes un punto importante. Para mis propios usos, no espero que a ningún operador de botnet le importe lo más mínimo, pero estoy publicando el código fuente para cualquier persona que desee una seguridad decente para su aplicación web, y no puedo saber lo que otros podrían estar intentando proteger, o quiénes son sus enemigos
Jens Roland

No protegerá los secretos nacionales sin importar qué (los sistemas oficiales necesitan una certificación especial, y estoy bastante seguro de que nada construido en PHP puede calificar), pero todas las aplicaciones web necesitan autenticación segura, así que si estoy lanzando esto, ' d ser increíblemente irresponsable no utilizar las mejores prácticas en lo que pueda
Jens Roland

1
Entonces, mi respuesta corta es: estoy construyendo esto porque el 99.9% de los sitios web y aplicaciones tienen una seguridad espantosa (incluso en las grandes ligas: AOL, Twitter, Myspace han sido comprometidos antes), y en la mayoría de los casos porque están utilizando bibliotecas de autenticación de mala calidad.
Jens Roland el

Además, lea el documento "A Catch A Predator" de Niels Provos et al. del proceso USENIX 2008 (enlace: usenix.org/events/sec08/tech/small.html ) Es una revelación : 2 meses, un honeypot: 368,000 ataques de casi 30,000 IP diferentes, ¡provenientes de más de 5,600 botnets!
Jens Roland el

5

Para resumir el esquema de Jens en un diagrama de transición de pseudoestado / base de reglas:

  1. usuario + contraseña -> entrada
  2. usuario +! contraseña -> denegado
  3. usuario + conocido_IP (usuario) -> puerta principal, // never throttle
  4. user + unknown_IP (usuario) -> catflap
  5. (#denied> n) a través de catflaps (sitio) -> throttle catflaps (sitio) // slow the bots
  6. catflap + acelerador + contraseña + captcha -> entrada // humans still welcome
  7. catflap + acelerador + contraseña +! captcha -> denegado // a correct guess from a bot

Observaciones:

  • Nunca estrangule la puerta delantera. La policía estatal de Elbon tiene su computadora en su casa, pero no puede interrogarlo. La fuerza bruta es un enfoque viable desde su computadora.
  • Si proporciona un "¿Olvidó su contraseña?" enlace, entonces su cuenta de correo electrónico se convierte en parte de la superficie de ataque.

Estas observaciones cubren un tipo diferente de ataque a los que estás tratando de contrarrestar.


Absolutamente la cuenta de correo electrónico es parte de la superficie de ataque. Tengo un conjunto de supuestos de límite superior sobre la seguridad que proporcionará mi estrategia, y el límite más bajo es la seguridad del correo electrónico del usuario. Si un atacante infringe el correo electrónico de un usuario, todas las apuestas están canceladas.
Jens Roland el

Además, creo que su diagrama de transición de estado necesita un par de detalles: # 3 y # 4 deben incluir contraseña; # 1 y # 2 deben incluir conocido_IP (usuario) ya que un inicio de sesión siempre tiene una IP conocida o desconocida; y # 6 es 'entrada a pesar del acelerador'
Jens Roland

4

Parece que estás intentando defenderte de la fuerza bruta lenta y distribuida . No hay mucho que puedas hacer al respecto. Estamos utilizando una PKI y no hay inicios de sesión de contraseña. Ayuda, pero si sus clientes tienen posibilidades de estaciones de trabajo de vez en cuando, esto no es muy aplicable.


En realidad, fuerza bruta rápida también. Tenía la esperanza de ser un poco indulgente con la fuerza bruta del usuario fijo (estrangulamiento de solo 20 segundos), pero en un sitio con 50k usuarios, eso haría posible la fuerza bruta rápida del usuario variable (suponiendo más de 20 segundos para recorrer los usuarios). Y eso, como dicen, apestaría ...
Jens Roland

Bien, la fuerza bruta rápida de un solo host usa iptables o cualquier firewall que use.
Björn Raupach

Me refería a la fuerza bruta rápida distribuida. Es raro pero es potencialmente muy desagradable
Jens Roland

3

Descargo de responsabilidad: trabajo para una empresa de dos factores, pero no estoy aquí para enchufarlo. Aquí hay algunas observaciones.

Las cookies se pueden robar con XSS y el navegador vulns. Los usuarios suelen cambiar de navegador o borrar sus cookies.

Las direcciones IP de origen son simultáneamente dinámicamente variables y suplantables.

Captcha es útil, pero no autentica a un humano específico.

Múltiples métodos se pueden combinar con éxito, pero el buen gusto está en orden.

La complejidad de la contraseña es buena, cualquier cosa basada en contraseña depende de manera crítica de que las contraseñas tengan suficiente entropía. En mi humilde opinión, una contraseña segura escrita en una ubicación física segura es mejor que una contraseña débil en la memoria. Las personas saben cómo evaluar la seguridad de los documentos en papel mucho mejor de lo que saben cómo calcular la entropía efectiva en el nombre de su perro cuando se usa como contraseña para tres sitios web diferentes. Considere dar a los usuarios la posibilidad de imprimir una página grande o pequeña llena de códigos de acceso de un solo uso.

Las preguntas de seguridad como "cuál era su mascota de la escuela secundaria" son en su mayoría otra forma pésima de "algo que usted sabe", la mayoría de ellas son fácilmente adivinables o de dominio público.

Como notó, la limitación de los intentos fallidos de inicio de sesión es una compensación entre la prevención de ataques de fuerza bruta y la facilidad de DoSing una cuenta. Las políticas de bloqueo agresivo pueden reflejar una falta de confianza en la entropía de contraseña.

Personalmente, no veo el beneficio de hacer cumplir la caducidad de la contraseña en un sitio web de todos modos. El atacante obtiene su contraseña una vez, puede cambiarla y cumplir con esa política tan fácilmente como usted. Quizás un beneficio es que el usuario podría notarlo antes si el atacante cambia la contraseña de la cuenta. Aún mejor sería si el usuario fuera notificado de alguna manera antes de que el atacante obtuviera acceso. Los mensajes como "N intentos fallidos desde el último inicio de sesión" son útiles a este respecto.

La mejor seguridad proviene de un segundo factor de autenticación que está fuera de banda en relación con el primero. Como dijiste, los tokens de hardware en "algo que tienes" son geniales, pero muchos (no todos) tienen una sobrecarga administrativa real asociada con su distribución. No conozco ninguna solución biométrica "algo que seas" buena para los sitios web. Algunas soluciones de dos factores funcionan con proveedores de OpenID, algunas tienen SDK de PHP / Perl / Python.


Todos los puntos excelentes: no podría estar más de acuerdo. El punto sobre la inseguridad de las cookies es muy válido, pero sin un segundo factor de tokens físicos o contraseñas de un solo uso (distribuidas a través de una línea segura) realmente no se puede proteger contra un punto final vulnerable. Si la caja / navegador del usuario se ve comprometida, también lo son sus inicios de sesión.
Jens Roland

1

Mi mayor recomendación es simplemente asegurarme de mantener informados a los usuarios de los intentos de inicio de sesión incorrectos en sus cuentas: es probable de su contraseña mucho más en serio si se les presenta evidencia de que alguien realmente está tratando de ingresar a su cuenta .

De hecho, atrapé a alguien que pirateó la cuenta de MySpace de mi hermano porque habían intentado ingresar a la cuenta de Gmail que configuré para él y usé la función 'restablecer mi contraseña por correo electrónico' ... que fue a mi bandeja de entrada.


1
  1. ¿Qué hay de requerir una contraseña de un solo uso antes de ingresar su contraseña normal? ¿Eso haría muy obvio que alguien estaba atacando antes de tener muchas oportunidades de adivinar la contraseña principal?

  2. Mantenga un conteo / tasa global de fallas de inicio de sesión, este es el indicador de un ataque, durante un ataque sea más estricto con respecto a las fallas de inicio de sesión, por ejemplo, prohíba las IP más rápidamente.


1) ¿Cómo implementaría una contraseña de un solo uso en una línea no segura y no autenticada? En otras palabras, ¿cuándo establece el usuario estas contraseñas de un solo uso? 2) Sí, esa es la esencia del n. ° 4 en mi lista, el límite de intentos fallidos en todo el sitio. La desventaja es la oportunidad DoS que abre.
Jens Roland el

0

No creo que haya una respuesta perfecta, pero me sentiría inclinado a tratar de confundir a los robots si se detecta un ataque.

Fuera de mi mente:

Cambie a una pantalla de inicio de sesión alternativa. Tiene varios espacios en blanco de nombre de usuario y contraseña que realmente aparecen, pero solo uno de ellos está en el lugar correcto. Los nombres de los campos son ALEATORIOS --una clave de sesión se envía junto con la pantalla de inicio de sesión, el servidor puede averiguar qué campos son lo. Si tiene éxito o falla, se descarta, por lo que no puede intentar un ataque de repetición; si rechaza la contraseña, obtendrá una nueva ID de sesión.

Se supone que cualquier formulario que se envíe con datos en un campo incorrecto proviene de un robot: el inicio de sesión falla, punto y esa IP se limita. Asegúrese de que los nombres de campo aleatorios nunca coincidan con los nombres de campo legítimos para que alguien que usa algo que recuerde contraseñas no sea engañoso.

A continuación, ¿qué tal un tipo diferente de captcha: tiene una serie de preguntas que no causarán problemas a un humano. Sin embargo, NO son azar. Cuando comienza el ataque, todos reciben la pregunta # 1. Después de una hora, se descarta la pregunta n. ° 1, nunca se volverá a utilizar y todos recibirán la pregunta n. ° 2, y así sucesivamente.

El atacante no puede probar la descarga de la base de datos para colocarla en su robot debido a la naturaleza desechable de las preguntas. Tiene que enviar nuevas instrucciones a su botnet en una hora para poder hacer cualquier cosa.


La pantalla de inicio de sesión alternativa suena como para confundir a los humanos más que a las máquinas, francamente. Por supuesto, suponemos que el atacante habría verificado nuestras medidas de seguridad de antemano. Podría haber ajustado fácilmente su raspador para encontrar los campos correctamente colocados.
Jens Roland

Las preguntas de verificación humana se han hecho antes, y no es muy efectiva. Para un operador humano de botnet responder una pregunta por hora (después de lo cual la nueva respuesta se propagaría a los bots) durante un ataque sería bastante factible.
Jens Roland

Te estás perdiendo el punto. El atacante no puede verificar por adelantado porque solo muestra las defensas adicionales cuando aparece un ataque.
Loren Pechtel

Claro, el humano podía ver cuál era la pregunta, pero tiene que comunicarlo a todos sus robots. Esa es una ruta de comunicación que hace que sea más fácil derribar la botnet.
Loren Pechtel

No creo que me esté perdiendo el punto. No me refiero a que hubiera ejecutado un ataque previamente para verificar nuestras medidas de seguridad, me refiero a que habría leído este hilo y verificado el código fuente (abierto) para verificar las debilidades :)
Jens Roland

0

Dado que varias personas incluyeron CAPTCHA como un mecanismo humano alternativo, estoy agregando una pregunta anterior de StackOverflow e hilo sobre la efectividad de CAPTCHA.

¿Se ha agrietado / pirateado / OCR'd / derrotado / roto reCaptcha?

El uso de CAPTCHA no limita las mejoras de su limitación y otras sugerencias, pero creo que la cantidad de respuestas que incluyen CAPTCHA como alternativa debe considerar los métodos basados ​​en humanos disponibles para las personas que buscan romper la seguridad.


0

También puede acelerar según la seguridad de la contraseña de un usuario.

Cuando un usuario registra o cambia su contraseña, usted calcula una calificación de fortaleza para su contraseña, digamos entre 1 y 10.

Algo así como "contraseña" obtiene un 1, mientras que "c6eqapRepe7et * Awr @ ch" puede obtener un puntaje de 9 o 10 y cuanto mayor sea el puntaje, más tiempo demorará la aceleración.


2
Entiendo la idea, pero eso indirectamente filtraría información sobre la contraseña, lo que le permitiría al atacante saber si vale la pena hackear una contraseña o no. Puede parecer un poco teórico, pero muchos usuarios reutilizan las contraseñas, por lo que si quiero entrar en Strong_Throttling_Website.com simplemente puedo atacar cuentas (privilegiadas) al azar hasta que encuentre un usuario, 'Freddy', que tiene una contraseña débil (es decir, aceleración temprana), luego vaya a Less_Secure_Website.edu y realice un ataque de diccionario fácil en la cuenta de Freddy allí. Es un poco complicado, pero ciertamente factible en la práctica.
Jens Roland

0

La primera respuesta que generalmente escucho cuando hago esta pregunta es cambiar los puertos, pero olvídate de eso y simplemente deshabilita IPv4. Si solo permite clientes de redes IPv6, ya no rezará por un escaneo de red simple y los atacantes recurrirán a las búsquedas de DNS. No ejecute en la misma dirección que su Apache (AAAA) / Sendmail (MX-> AAAA) / lo que le ha dado a todos (AAAA). Asegúrate de que tu zona no pueda ser transferida, ¿estás esperando que alguien pueda descargar tu zona?

Si los bots encuentran que su servidor configura nuevos nombres de host, simplemente agregue algunas tonterías a sus nombres de host y cambie su dirección. Deje los nombres antiguos e incluso configure ** nombres de honeypot para que la red de bots agote el tiempo de espera.

** Pruebe sus registros inversos (PTR) (bajo ip6.arpa.) Para ver si se pueden usar para poner a cero en los / 4 que tienen registros VS / 4 que no. IE Típicamente, ip6.arpa tendría ~ 32 "." S en una dirección, pero intentar con los últimos que faltan podría eludir los bloques de red que tienen registros VS otros que no. Si lleva eso más allá, es posible omitir grandes porciones del espacio de direcciones.

En el peor de los casos, los usuarios tendrán que configurar un túnel IPv6, no es como si tuvieran que ir tan lejos como VPNing en una DMZ ... Aunque uno se pregunta por qué esa no es la primera opción.

También Kerberos es genial, pero IMHO LDAP explota (¿Qué tiene de malo técnicamente NISPlus? He leído que Sun decidió que los usuarios querían LDAP y por eso dejaron NIS +). Kerberos funciona bien sin LDAP o NIS, solo tiene que administrar los usuarios host por host. El uso de Kerberos le brinda una PKI fácil de usar, si no automatizada.


0

Un poco tarde aquí, pero estaba pensando, asumiendo un caso difícil: el atacante usa muchas direcciones IP aleatorias, nombres de usuario aleatorios y una contraseña aleatoria seleccionada de una lista de los 10,000 más populares.

Una cosa que podría hacer, especialmente si el sistema parece estar bajo ataque, ya que hay muchos intentos de contraseña incorrecta en el sistema y especialmente si la contraseña es de baja entropía es hacer una pregunta secundaria como, por ejemplo, cuáles son los nombres de sus padres. . Si un atacante llega a un millón de cuentas probando la contraseña 'contraseña1', hay una buena posibilidad de que obtenga mucho, pero sus probabilidades de obtener también los nombres correctos reducirían drásticamente los éxitos.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.