Protección de fuerza bruta en PHP

Si tiene un sistema donde los usuarios pueden suscribirse y elegir sus propias contraseñas, probablemente sea un objetivo de ataques de fuerza bruta como un ataque de diccionario . Puede limitar este problema mostrando al usuario qué tan segura es su contraseña. Sin embargo, obligar a los usuarios a ingresar una contraseña realmente segura los molestará, ya que les gusta algo que pueden recordar.

Otra forma de muro que puede colocar es bloquear una dirección IP durante unos minutos ante una serie de errores de inicio de sesión. Esta no es una protección a prueba de agua, pero el hacker ahora requiere una botnet para realizar el ataque de fuerza bruta. Este es un obstáculo que debería mantener a raya a los piratas informáticos casuales y a los guionistas. Entonces, según los datos que está protegiendo, esta debería ser una defensa decente.

Configurar esta defensa no es difícil. Mostraré un ejemplo de cómo hacer esto con el caché de usuario de APC .

<?php
$apc_key
= "{$_SERVER['SERVER_NAME']}~login:{$_SERVER['REMOTE_ADDR']}";
$tries
= (int)apc_fetch($apc_key);
if ($tries >= 10) {
header
("HTTP/1.1 429 Too Many Requests");
echo
"You've exceeded the number of login attempts. We've blocked IP address {$_SERVER['REMOTE_ADDR']} for a few minutes.";
exit();
}

$success
= login($_POST['username'], $_POST['password']);
if (!$success) {
apcu_inc
($apc_key, $tries+1, 600); # store tries for 10 minutes
} else {
apc_delete
($apc_key);
}

Aumentando el tiempo de bloqueo

El bloqueo de una IP puede afectar a toda una oficina, lo que puede resultar molesto. Comenzar con un tiempo de espera bajo y aumentarlo cada vez que se bloquea una IP ayudará en su contra.

<?php
$apc_key
= "{$_SERVER['SERVER_NAME']}~login:{$_SERVER['REMOTE_ADDR']}";
$apc_blocked_key
= "{$_SERVER['SERVER_NAME']}~login-blocked:{$_SERVER['REMOTE_ADDR']}";

$tries
= (int)apc_fetch($apc_key);
if ($tries >= 10) {
header
("HTTP/1.1 429 Too Many Requests");
echo
"You've exceeded the number of login attempts. We've blocked IP address {$_SERVER['REMOTE_ADDR']} for a few minutes.";
exit();
}

$success
= login($_POST['username'], $_POST['password']);
if (!$success) {
$blocked
= (int)apc_fetch($apc_blocked_key);

apc_store
($apc_key, $tries+1, pow(2, $blocked+1)*60); # store tries for 2^(x+1) minutes: 2, 4, 8, 16, ...
apc_store
($apc_blocked_key, $blocked+1, 86400); # store number of times blocked for 24 hours
} else {
apc_delete
($apc_key);
apc_delete
($apc_blocked_key);
}