Security is essential for every WordPress site owner. While the platform provides many built-in security features, brute force attacks remain a persistent threat. These attacks involve multiple login attempts by hackers trying to guess passwords. This guide will show you a free, simple yet powerful solution that doesn’t require any plugins. It limits login attempts and locks out potential threats, helping keep your WordPress site safe.
Why Limit Login Attempts?
Limiting login attempts is a proven strategy for reducing the risk of brute force attacks. By restricting the number of times a user can attempt to log in, you can effectively stop bots and malicious users from guessing passwords and accessing your website.
This solution will:
- Track login attempts by IP address.
- Lock out users after three failed login attempts.
- Gradually increase the lockout period after repeated failed attempts.
- Reset login attempt counts after a successful login.
Let’s break down the code that accomplishes this.
Step 1: Tracking and Blocking Failed Login Attempts
When users attempt to log in, we need to monitor their activity and count their failed attempts.
function check_attempted_login($user, $username, $password) {
$ip_address = sanitize_text_field( $_SERVER['REMOTE_ADDR'] );
$transient_key = 'attempted_login_' . $ip_address;
// Retrieve attempt data
$data = get_transient($transient_key);
// If the user has exceeded the allowed number of attempts
if ($data && $data['tried'] >= 3) {
$until = get_option('_transient_timeout_' . $transient_key);
$time_remaining = $until - time();
if ($time_remaining > 0) {
return new WP_Error(
'too_many_tried',
sprintf( __( '<strong>ERROR</strong>: You have reached the authentication limit. Please try again in %s.', 'simplelimitedlogin' ), time_to_go($until) )
);
}
}
return $user;
}
add_filter('authenticate', 'check_attempted_login', 30, 3);
This function checks the user’s IP address and monitors the number of failed login attempts. If the user exceeds three failed attempts, they are locked out for a specific period, with a warning message explaining how long they must wait before trying again.
Step 2: Handling Failed Logins
Next, we increase the failed attempt count each time a login fails.
function login_failed($username) {
$ip_address = sanitize_text_field( $_SERVER['REMOTE_ADDR'] );
$transient_key = 'attempted_login_' . $ip_address;
$lockout_counter_key = 'lockout_counter_' . $ip_address;
$data = get_transient($transient_key);
$lockout_count = get_transient($lockout_counter_key);
if ($data) {
$data['tried']++;
} else {
$data = array('tried' => 1);
}
if ($data['tried'] > 3) return;
if (!$lockout_count) $lockout_count = 0;
if ($data['tried'] == 3) {
$lockout_count++;
set_transient($lockout_counter_key, $lockout_count, 86400);
}
// Adjust lockout duration based on number of previous lockouts
$transient_duration = ($lockout_count >= 3) ? 86400 : 1200;
set_transient($transient_key, $data, $transient_duration);
}
add_action('wp_login_failed', 'login_failed', 10, 1);
In this function, each failed attempt is tracked using WordPress transients, temporary options stored in the database. When a user reaches three failed attempts, they are locked out, and the lockout duration increases after repeated failures.
Step 3: Resetting on Successful Login
Upon a successful login, it’s essential to clear any lockout data so that users aren’t blocked after authenticating correctly.
function login_success($user) {
$ip_address = sanitize_text_field( $_SERVER['REMOTE_ADDR'] );
$transient_key = 'attempted_login_' . $ip_address;
$lockout_counter_key = 'lockout_counter_' . $ip_address;
// Clear lockout data on successful login
delete_transient($transient_key);
delete_transient($lockout_counter_key);
}
add_action('wp_login', 'login_success', 10, 1);
This function removes the transients storing the failed login attempts and lockout counter upon successful authentication.
Step 4: Displaying Time Remaining in Lockout
To improve user experience, it’s helpful to provide a human-readable countdown of how much time remains before they can try logging in again.
function time_to_go( $timestamp ) {
$now = time();
return human_time_diff( $now, $timestamp );
}
This utility function calculates the time difference between the current time and the lockout expiration, ensuring users know when they can try again.
Step 5: Loading the Child Theme’s Text Domain for Translations
To make your custom login limit messages multilingual-friendly, it’s essential to load the child theme’s text domain. This allows you to localize the text strings, ensuring they can be translated into different languages.
// Load the child theme's text domain
function child_theme_setup() {
load_child_theme_textdomain( 'simplelimitedlogin', get_stylesheet_directory() . '/languages' );
}
add_action( 'after_setup_theme', 'child_theme_setup' );
or example, if you want to add Greek translations, you need to create a .po
file named el.po
for Greek. This file should be placed in the /languages
folder inside your child theme directory.
The contents of the el.po
file should include the following translation for the error message:
msgid "<strong>ERROR</strong>: You have reached the authentication limit. Please try again in %s."
msgstr "<strong>ΣΦΑΛΜΑ</strong>: Έχετε φτάσει το όριο αυθεντικοποίησης. Παρακαλώ δοκιμάστε ξανά σε %s."
This will ensure that Greek-speaking users receive the appropriate message in their language if they exceed the login attempt limit.
Conclusion
By implementing this solution, you’ve added an extra layer of security to your WordPress site. This custom code limits login attempts and protects against brute force attacks, locking out users after repeated failures while providing them with useful information on when they can attempt to log in again.
Best of all, this solution doesn’t require any external plugins. You simply need to add the functions to your theme’s functions.php
file. Many plugins offer similar features but often require a subscription to unlock their full range of options. With this custom solution, you enhance security without additional costs or dependencies. Minimizing dependencies helps keep your site faster and more efficient.
Additionally, you may consider configuring your site to send email notifications to the administrator for failed login attempts. This extra step can provide valuable oversight and keep you informed about potential security issues.
For more WordPress tips and tech tutorials, stay tuned to our blog!
Subscribe to our newsletter!
+ There are no comments
Add yours