Pregunta

Estaba leyendo este post La guía definitiva para formar basado en la autenticación de sitios web en la Prevención de la Rápido-Fuego de Intentos de inicio de Sesión.

Mejor practica #1:Un corto retardo de tiempo que se incrementa con el número de intentos fallidos, como:

1 intento fallido = sin retardo
2 intentos fallidos = 2 seg. de retraso
3 intentos fallidos = 4 seg de retraso
4 intentos fallidos = 8 seg de retraso
5 intentos fallidos = 16 segundos de retraso
etc.

DoS de atacar este esquema sería muy poco práctico, pero, por otro lado, potencialmente devastadores, como el retardo aumenta de forma exponencial.

Tengo curiosidad de cómo podría implementar algo como esto para mi sistema de login en PHP?

¿Fue útil?

Solución

Puede no sólo prevenir ataques de denegación de servicio por el encadenamiento de la estrangulación a una sola dirección IP o nombre de usuario. Diablos, ni siquiera se puede realmente prevenir los intentos de inicio de sesión de tiro rápido utilizando este método.

¿Por qué? Debido a que el ataque puede abarcar varias IPs y cuentas de usuario para el bien de pasar por sus intentos de estrangulación.

he visto publicado en otro lugar que lo ideal es que ser el seguimiento de todos los intentos fallidos de autenticación a través del 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,
    INDEX `attempted_idx` (`attempted`)
) engine=InnoDB charset=UTF8;

Una nota rápida en el campo dirección_ip:. Puede almacenar los datos y recuperar los datos, respectivamente, con INET_ATON () y inet_ntoa (), que equivale esencialmente a la conversión de una dirección IP a y desde un entero sin signo

# example of insertion
INSERT INTO failed_logins SET username = 'example', ip_address = INET_ATON('192.168.0.1'), attempted = CURRENT_TIMESTAMP;
# example of selection
SELECT id, username, INET_NTOA(ip_address) AS ip_address, attempted;

Decidir sobre determinados umbrales de retardo en base a la general número de inicios de sesión fallidos en una cantidad dada de tiempo (15 minutos en este ejemplo). Debe basar esto en datos estadísticos sacaron de su mesa failed_logins como lo hará cambian con el tiempo basado en el número de usuarios y cuántos de ellos puede recordar (y tipo) de su contraseña.


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

consultar la tabla en cada intento de inicio de sesión fallido para encontrar el número de intentos fallidos para un período determinado de tiempo, 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 es encima de su límite, ya sea hacer cumplir de estrangulación o forzar a todos los de usar un código de imagen (es decir reCaptcha) hasta que el número de intentos fallidos en el período de tiempo dado de usuario es menor que el umbral .

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

// retrieve the latest failed login attempts
$sql = 'SELECT MAX(attempted) AS attempted FROM failed_logins';
$result = mysql_query($sql);
if (mysql_affected_rows($result) > 0) {
    $row = mysql_fetch_assoc($result);

    $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)';
    $result = mysql_query($sql);
    if (mysql_affected_rows($result) > 0) {
        // get the returned row
        $row = mysql_fetch_assoc($result);
        $failed_attempts = (int) $row['failed'];

        // 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;
            }
        }        
    }
}

de reCAPTCHA a un cierto umbral se aseguraría de que un ataque desde múltiples frentes se detuvo y los usuarios normales del sitio no experimentaría un retraso significativo de intentos fallidos de conexión legítimos.

Otros consejos

Hay tres enfoques básicos:. Información de la sesión tienda, tienda de galletas de información o almacenar información de IP

Si utiliza la información de sesión del usuario final (atacante) podría invocar la fuerza a nuevas sesiones, eludir su táctica, y luego ingresar nuevamente sin demora. Las sesiones son bastante simple de implementar, simplemente almacenar la última vez conocida inicio de sesión del usuario en una variable de sesión, coinciden en contra de la hora actual, y asegúrese de que el retraso ha sido lo suficientemente larga.

Si utiliza las cookies, el atacante puede simplemente rechazar las cookies, en definitiva, esto realmente no es algo viable.

Si realiza el seguimiento de direcciones IP que necesita para almacenar intentos de conexión desde una dirección IP de alguna manera, preferiblemente en una base de datos. Cuando un usuario intenta conectarse, simplemente actualizar su lista de IPs registrado. Usted debe purgar esta tabla en un intervalo razonable, el vertido de direcciones IP que no han estado activos en algún tiempo. La trampa (siempre hay una trampa), es que algunos usuarios pueden terminar compartiendo una dirección IP, y en sus condiciones de contorno retrasos pueden afectar a los usuarios inadvertidamente. Puesto que usted está realizando un seguimiento inicios de sesión fallidos, y los inicios de sesión única fallidos, esto no debe causar demasiado dolor.

Las necesidades del proceso de inicio de sesión reducen su velocidad de inicio de sesión tanto con y sin éxito. El propio intento de acceso no debe ser más rápido que alrededor de 1 segundo. Si es así, la fuerza bruta utiliza el retardo de saber que el intento falló porque el éxito es más corto que el fracaso. Luego, más combinaciones pueden ser evaluadas por segundo.

El número de intentos de inicio de sesión simultáneas por máquina necesita ser limitado por el equilibrador de carga. Por último, sólo tiene que realizar un seguimiento de si el mismo usuario o la contraseña son reutilizados por más de un usuario / contraseña intento de inicio de sesión. Los seres humanos no pueden escribir más rápido que aproximadamente 200 palabras por minite. Así, inicio de sesión sucesiva o simultánea intenta más rápido de 200 palabras por minite son de un conjunto de máquinas. Estos por lo tanto se pueden canalizar a una lista de negro de forma segura, ya que no es su cliente. tiempos en lista negra por host no necesitan ser mayor de aproximadamente 1 segundo. Esto nunca será un inconveniente para un ser humano, pero hace estragos en un intento de fuerza bruta ya sea en paralelo o en serie.

2 * 10 ^ 19 combinaciones en una combinación por segundo, correr en paralelo en 4 mil millones de direcciones IP independientes, se llevará a 158 años para agotar como un espacio de búsqueda. Para una duración de un día por cada usuario frente a 4 mil millones de atacantes, necesita una contraseña alfanumérica aleatoria 9 lugares a largo como mínimo. Considere la capacitación de los usuarios en las frases de paso de al menos 13 lugares de largo, 1.7 * 10 ^ 20 combinaciones.

Este retraso, motivará al atacante para robar su archivo hash de la contraseña en lugar de la fuerza bruta su sitio. El uso aprobado, nombrado, técnicas de hashing. La prohibición de toda la población de Internet IP durante un segundo, se limitará el efecto de los ataques paralelos sin dealy un humano podría apreciar. Por último, si el sistema permite que más de 1.000 intentos fallidos de inicio de sesión en un segundo sin algún tipo de respuesta a la prohibición de los sistemas, a continuación, sus planes de seguridad tienen problemas más grandes para trabajar. Fijar que la respuesta automatizado primero de todos.

session_start();
$_SESSION['hit'] += 1; // Only Increase on Failed Attempts
$delays = array(1=>0, 2=>2, 3=>4, 4=>8, 5=>16); // Array of # of Attempts => Secs

sleep($delays[$_SESSION['hit']]); // Sleep for that Duration.

o según lo sugerido por Cyro:

sleep(2 ^ (intval($_SESSION['hit']) - 1));

Es un poco duro, pero los componentes básicos están ahí. Si actualiza esta página, cada vez que se actualiza el retraso se alargará.

También podría mantener las cuentas en una base de datos, donde se comprueba el número de intentos fallidos por IP. Mediante su uso basado en IP y mantener los datos de su lado, se evita que el usuario sea capaz de borrar sus cookies para detener la demora.

Básicamente, el código principio sería:

$count = get_attempts(); // Get the Number of Attempts

sleep(2 ^ (intval($count) - 1));

function get_attempts()
{
    $result = mysql_query("SELECT FROM TABLE WHERE IP=\"".$_SERVER['REMOTE_ADDR']."\"");
    if(mysql_num_rows($result) > 0)
    {
        $array = mysql_fetch_assoc($array);
        return $array['Hits'];
    }
    else
    {
        return 0;
    }
}

tienda fracasan los intentos en la base de datos a través de IP. (Puesto que usted tiene un sistema de inicio de sesión, supongo que sabe bien cómo hacer esto.)

Obviamente, las sesiones es un método tentador, pero alguien muy dedicado puede darse cuenta fácilmente de que simplemente pueden eliminar su cookie de sesión de intentos fallidos con el fin de eludir el acelerador por completo.

En un intento de conexión, ir a buscar cuántos reciente (por ejemplo, los últimos 15 minutos) de inicio de sesión intentos hubo, y el tiempo del último intento.

$failed_attempts = 3; // for example
$latest_attempt = 1263874972; // again, for example
$delay_in_seconds = pow(2, $failed_attempts); // that's 2 to the $failed_attempts power
$remaining_delay = time() - $latest_attempt - $delay_in_seconds;
if($remaining_delay > 0) {
    echo "Wait $remaining_delay more seconds, silly!";
}

Puede utilizar las sesiones. Cada vez que el usuario falla un inicio de sesión, se aumenta el valor que almacena el número de intentos. Usted puede calcular el retardo necesario desde el número de intentos, o puede establecer el tiempo real que se permite que el usuario intente de nuevo en la sesión también.

Un método más fiable sería la de almacenar los intentos y probarlos en tiempo nuevo en la base de datos para esa dirección ip en particular.

En mi humilde opinión, la defensa contra ataques DOS es mejor tratada a nivel de servidor web (o tal vez incluso en el hardware de la red), no en su código PHP.

I en general, crear la historia de usuario y tablas de intentos de inicio de sesión. La tabla intento sería ingrese nombre de usuario, contraseña, dirección IP, etc. consulta en la tabla para ver si es necesario retrasar. Yo recomendaría el bloqueo total de intentos para mayores de 20 en un momento dado (una hora por ejemplo).

De acuerdo con la discusión anterior, las sesiones, cookies y direcciones IP no son eficaces - todos pueden ser manipulados por el atacante

.

Si desea evitar ataques de fuerza bruta, entonces la única solución práctica consiste en basar el número de intentos en el nombre de usuario proporcionado, sin embargo en cuenta que esto permite que el atacante DOS el sitio mediante el bloqueo de los usuarios válidos de iniciar la sesión.

por ejemplo.

$valid=check_auth($_POST['USERNAME'],$_POST['PASSWD']);
$delay=get_delay($_POST['USERNAME'],$valid);

if (!$valid) {
   header("Location: login.php");
   exit;
}
...
function get_delay($username,$authenticated)
{
    $loginfile=SOME_BASE_DIR . md5($username);
    if (@filemtime($loginfile)<time()-8600) {
       // last login was never or over a day ago
       return 0;
    }
    $attempts=(integer)file_get_contents($loginfile);
    $delay=$attempts ? pow(2,$attempts) : 0;
    $next_value=$authenticated ? 0 : $attempts + 1;
    file_put_contents($loginfile, $next_value);
    sleep($delay); // NB this is done regardless if passwd valid
    // you might want to put in your own garbage collection here
 }

Tenga en cuenta que tal como está escrito, este procedimiento se filtra la información de seguridad - es decir, será posible para alguien atacando el sistema para ver cuando un usuario se conecta (el tiempo de respuesta para el intento de los atacantes se reducirá a 0). Que puede que al sintonizar el algoritmo de modo que el retardo se calcula basándose en el retardo anterior y la marca de tiempo en el archivo.

HTH

C.

Las Cookies de sesión o basados en métodos son, por supuesto, inútil en este caso.La solicitud se ha de comprobar la dirección IP o marcas de tiempo (o ambos) de los anteriores intentos de inicio de sesión.

Una IP puede ser evitado si el atacante tiene más de una dirección IP para iniciar su las solicitudes de y puede ser problemático si varios usuarios conectarse a su servidor desde la misma IP.En el último caso, alguien fallando inicio de sesión para varios tiempos de prevenir todos los que comparten el mismo IP de inicio de sesión con nombre de usuario para un determinado período de tiempo.

Una marca de verificación tiene el mismo problema de antes:todo el mundo puede evitar que todos los demás de inicio de sesión en una cuenta, en particular, simplemente por intentar varias veces.El uso de un captcha en lugar de una larga espera para el último intento es probablemente una buena solución.

El único extra de cosas, el sistema de login debe evitar son las condiciones de carrera en el intento de comprobar la función.Por ejemplo, en el siguiente pseudocódigo

$time = get_latest_attempt_timestamp($username);
$attempts = get_latest_attempt_number($username);

if (is_valid_request($time, $attempts)) {
    do_login($username, $password);
} else {
    increment_attempt_number($username);
    display_error($attempts);
}

¿Qué sucede si un atacante envía simultánea las solicitudes para la página de inicio de sesión?Probablemente todas las peticiones de ejecución de la misma prioridad, y lo más probable es que la solicitud llegue a la increment_attempt_number la instrucción antes de que los demás están en el pasado la 2ª línea.Para cada solicitud que recibe el mismo $y $los intentos de valor y se ejecuta.La prevención de este tipo de problemas de seguridad puede ser difícil para aplicaciones complejas y consiste en el bloqueo y desbloqueo de algunas tablas y filas de la base de datos, por supuesto, la desaceleración de la aplicación.

La respuesta corta es: No haga esto. Usted no va a protegerse de los ataques de fuerza bruta, que incluso podría empeorar su situación.

Ninguna de las soluciones propuestas funcionaría. Si se utiliza el IP como cualquier parámetro de estrangulación, el atacante acaba de atravesar el ataque a través de un gran número de direcciones IP. Si utiliza la sesión (cookies), el atacante simplemente dejar las cookies. La suma de todo lo que ocurre es, que no hay absolutamente nada que un atacante forzar bruta no pudo superar.

Hay una cosa, sin embargo - que sólo se basan en el nombre de usuario que intentó conectarse Así, sin mirar a todos los demás parámetros que realizar un seguimiento de la frecuencia con la que un usuario intentó iniciar la sesión y del acelerador.. Sin embargo, un atacante quiere hacerle daño. Si se reconoce esto, lo hará también sólo bruta fuerza los nombres de usuario.

Esto dará lugar a la casi totalidad de sus usuarios está limitando a su valor máximo cuando intentan iniciar sesión. Su sitio web será inútil. Atacante:. Éxito

Se puede retrasar la revisión de la contraseña, en general, por alrededor de 200 ms - el usuario del sitio web casi no se dará cuenta de que. Pero un bruto forzador hará. (Una vez que pudiera extenderse a lo largo IPs) Sin embargo, nada de todo esto le protegerá de ataques de fuerza bruta o ataques DDoS -. Como pueda no programáticamente

La única manera de hacerlo es usando la infraestructura.

Debe utilizar bcrypt en lugar de MD5 o SHA-x para discutir sus contraseñas, esto hará que el descifrado de contraseñas mucho más difícil si alguien roba su base de datos (porque supongo que usted está en un servidor compartido o gestionado)

Lo siento por decepcionarte, pero todas las soluciones aquí tienen una debilidad y no hay manera de superarlos dentro de la lógica de fondo.

cballuo proporciona una excelente respuesta. Sólo quería devolver el favor de proporcionar una versión actualizada que mysqli soporta. Me ha modificado ligeramente las columnas de tabla / campo en los sqls y otras cosas pequeñas pero debería ayudar a cualquier persona que busca el equivalente mysqli.

function get_multiple_rows($result) {
  $rows = array();
  while($row = $result->fetch_assoc()) {
    $rows[] = $row;
  }
  return $rows;
}

$throttle = array(10 => 1, 20 => 2, 30 => 5);

$query = "SELECT MAX(time) AS attempted FROM failed_logins";    

if ($result = $mysqli->query($query)) {

    $rows = get_multiple_rows($result);

$result->free();

$latest_attempt = (int) date('U', strtotime($rows[0]['attempted'])); 

$query = "SELECT COUNT(1) AS failed FROM failed_logins WHERE time > DATE_SUB(NOW(), 
INTERVAL 15 minute)";   

if ($result = $mysqli->query($query)) {

$rows = get_multiple_rows($result);

$result->free();

    $failed_attempts = (int) $rows[0]['failed'];

    krsort($throttle);
    foreach ($throttle as $attempts => $delay) {
        if ($failed_attempts > $attempts) {
                echo $failed_attempts;
                $remaining_delay = (time() - $latest_attempt) - $delay;

                if ($remaining_delay < 0) {
                echo 'You must wait ' . abs($remaining_delay) . ' seconds before your next login attempt';
                }                

            break;
        }
     }        
  }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top