You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/* * Hook for authentication for login through transients options (stored in 'wp_options' table) * This hook passes three parameters: $user, $username and $password. * In order to generate an error on login, you will need to return a WP_Error object * Currently it will throw an error if we have >= 2 attempts * * @link https://developer.wordpress.org/reference/hooks/authenticate/ */add_filter('authenticate', function($user, $username, $pass) {
/** Check if we have already transient for current login session */if(get_transient('wp_login_attempts_'.get_real_IP())) {
/** * Fallback for deleting transients (and their timeout_ parts) * If WordPress installation has disabled WP Cron, then there is no way to delete transients * Suppress error messages for delete_transient */if(get_transient('timeout_wp_login_attempts_'.get_real_IP()) && time() >= get_transient('timeout_wp_login_attempts_'.get_real_IP())) {
@delete_transient('wp_login_attempts_'.get_real_IP());
@delete_transient('timeout_wp_login_attempts_'.get_real_IP());
return$user;
}
/** Count number of attempts by visitor */$login_attempts = get_transient('wp_login_attempts_'.get_real_IP());
/** return a WP_Error object if >= 2 attempts */if(isset($login_attempts) && is_numeric($login_attempts) && $login_attempts >= 2) {
returnnewWP_Error('too_many_tried', sprintf( __( '<strong>ERROR</strong>: You have reached authentication limit. Attempts: %1$s.'), $login_attempts));
}
}
return$user;
}, 30, 3);
Count the number of failed logins
/* * Hook that fires after user login has failed * Increase count of failed attempts for current IP address and generate/update transient option * * @link https://developer.wordpress.org/reference/hooks/wp_login_failed/ */add_action('wp_login_failed', function($username) {
if(get_transient('wp_login_attempts_'.get_real_IP())) {
$login_attempts = get_transient('wp_login_attempts_'.get_real_IP());
$login_attempts++;
set_transient('wp_login_attempts_'.get_real_IP(), $login_attempts , 600);
} else {
set_transient('wp_login_attempts_'.get_real_IP(), 1, 600);
}
return$username;
}, 10, 1);
Get the real IP address of the attacker
/* * The get_real_IP() function will get us the attacker IP through safe 'REMOTE_ADDR' * Other methods such as 'HTTP_CLIENT_IP' can be easily faked/or possess security risk * Attacker can still spoof 'REMOTE_ADDR' but it should still serve the same purpose as we wanted * * return real IP or 0, which can be still used as universal blocking transient */if(!function_exists('get_real_IP')) {
functionget_real_IP() {
$IP = $_SERVER['REMOTE_ADDR'];
if(filter_var($IP, FILTER_VALIDATE_IP)) return$IP;
return0;
}
}
(Optional) Suppress the other error messages
/* * Hook that filters the error messages displayed above the login form * Suppress the error message such as The username <username> is not registered on this site * We added a custom error message for all login errors except login attempts * More login errors can be customized through WP_Error::get_error_codes() * * @link https://developer.wordpress.org/reference/hooks/login_errors/ */add_filter('login_errors', function($error) {
/** Return the login attempts the error message if visitor reached required number of failed login attempts */if(get_transient('wp_login_attempts_'.get_real_IP()) && str_contains($error, 'You have reached authentication limit')) return$error;
/** Our custom message for login error */return'Your IP: ' . get_real_IP() . ' was logged.';
});