Version Description
Download this release
Release Info
Developer | mvandemar |
Plugin | Login LockDown |
Version | 1.7.1 |
Comparing to | |
See all releases |
Code changes from version 1.6.1 to 1.7.1
- loginlockdown.php +124 -16
- readme.txt +11 -4
- version.txt +1 -1
loginlockdown.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
/*
|
3 |
Plugin Name: Login LockDown
|
4 |
Plugin URI: http://www.bad-neighborhood.com/
|
5 |
-
Version: v1.
|
6 |
Author: Michael VanDeMar
|
7 |
Description: Adds some extra security to WordPress by restricting the rate at which failed logins can be re-attempted from a given IP range. Distributed through <a href="http://www.bad-neighborhood.com/" target="_blank">Bad Neighborhood</a>.
|
8 |
*/
|
@@ -10,6 +10,12 @@ Description: Adds some extra security to WordPress by restricting the rate at wh
|
|
10 |
/*
|
11 |
== Change Log ==
|
12 |
*
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
* ver. 1.6.1 8-Mar-2014
|
14 |
* - fixed html glitch preventing options from being saved
|
15 |
*
|
@@ -131,14 +137,13 @@ function countFails($username = "") {
|
|
131 |
global $wpdb;
|
132 |
global $loginlockdownOptions;
|
133 |
$table_name = $wpdb->prefix . "login_fails";
|
134 |
-
$
|
135 |
-
$class_c = substr ($ip, 0 , strrpos ( $ip, "." ));
|
136 |
|
137 |
$numFailsquery = "SELECT COUNT(login_attempt_ID) FROM $table_name " .
|
138 |
"WHERE login_attempt_date + INTERVAL " .
|
139 |
$loginlockdownOptions['retries_within'] . " MINUTE > now() AND " .
|
140 |
"login_attempt_IP LIKE '%s'";
|
141 |
-
$numFailsquery = $wpdb->prepare( $numFailsquery, $
|
142 |
|
143 |
$numFails = $wpdb->get_var($numFailsquery);
|
144 |
return $numFails;
|
@@ -148,7 +153,7 @@ function incrementFails($username = "") {
|
|
148 |
global $wpdb;
|
149 |
global $loginlockdownOptions;
|
150 |
$table_name = $wpdb->prefix . "login_fails";
|
151 |
-
$
|
152 |
|
153 |
$username = sanitize_user($username);
|
154 |
$user = get_user_by('login',$username);
|
@@ -160,7 +165,7 @@ function incrementFails($username = "") {
|
|
160 |
}
|
161 |
$insert = "INSERT INTO " . $table_name . " (user_id, login_attempt_date, login_attempt_IP) " .
|
162 |
"VALUES ('" . $user_id . "', now(), '%s')";
|
163 |
-
$insert = $wpdb->prepare( $insert, $
|
164 |
$results = $wpdb->query($insert);
|
165 |
}
|
166 |
}
|
@@ -169,7 +174,7 @@ function lockDown($username = "") {
|
|
169 |
global $wpdb;
|
170 |
global $loginlockdownOptions;
|
171 |
$table_name = $wpdb->prefix . "lockdowns";
|
172 |
-
$
|
173 |
|
174 |
$username = sanitize_user($username);
|
175 |
$user = get_user_by('login',$username);
|
@@ -182,7 +187,7 @@ function lockDown($username = "") {
|
|
182 |
$insert = "INSERT INTO " . $table_name . " (user_id, lockdown_date, release_date, lockdown_IP) " .
|
183 |
"VALUES ('" . $user_id . "', now(), date_add(now(), INTERVAL " .
|
184 |
$loginlockdownOptions['lockout_length'] . " MINUTE), '%s')";
|
185 |
-
$insert = $wpdb->prepare( $insert, $
|
186 |
$results = $wpdb->query($insert);
|
187 |
}
|
188 |
}
|
@@ -190,13 +195,12 @@ function lockDown($username = "") {
|
|
190 |
function isLockedDown() {
|
191 |
global $wpdb;
|
192 |
$table_name = $wpdb->prefix . "lockdowns";
|
193 |
-
$
|
194 |
-
$class_c = substr ($ip, 0 , strrpos ( $ip, "." ));
|
195 |
|
196 |
$stillLockedquery = "SELECT user_id FROM $table_name " .
|
197 |
"WHERE release_date > now() AND " .
|
198 |
"lockdown_IP LIKE %s";
|
199 |
-
$stillLockedquery = $wpdb->prepare($stillLockedquery,$
|
200 |
|
201 |
$stillLocked = $wpdb->get_var($stillLockedquery);
|
202 |
|
@@ -232,6 +236,27 @@ function get_loginlockdownOptions() {
|
|
232 |
return $loginlockdownAdminOptions;
|
233 |
}
|
234 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
235 |
function print_loginlockdownAdminPage() {
|
236 |
global $wpdb;
|
237 |
$table_name = $wpdb->prefix . "lockdowns";
|
@@ -287,12 +312,24 @@ function print_loginlockdownAdminPage() {
|
|
287 |
$dalist = listLockedDown();
|
288 |
?>
|
289 |
<div class="wrap">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
290 |
<form method="post" action="<?php echo esc_attr($_SERVER["REQUEST_URI"]); ?>">
|
291 |
<?php
|
292 |
if ( function_exists('wp_nonce_field') )
|
293 |
wp_nonce_field('login-lockdown_update-options');
|
294 |
?>
|
295 |
-
|
296 |
<h3><?php _e('Max Login Retries', 'loginlockdown') ?></h3>
|
297 |
<p>Number of failed login attempts within the "Retry Time Period Restriction" (defined below) needed to trigger a LockDown.</p>
|
298 |
<p><input type="text" name="ll_max_login_retries" size="8" value="<?php echo esc_attr($loginlockdownAdminOptions['max_login_retries']); ?>"></p>
|
@@ -319,13 +356,20 @@ This helps others know about the plugin so they can protect their blogs as well
|
|
319 |
<div class="submit">
|
320 |
<input type="submit" class="button button-primary" name="update_loginlockdownSettings" value="<?php _e('Update Settings', 'loginlockdown') ?>" /></div>
|
321 |
</form>
|
322 |
-
|
323 |
<form method="post" action="<?php echo esc_attr($_SERVER["REQUEST_URI"]); ?>">
|
324 |
<?php
|
325 |
if ( function_exists('wp_nonce_field') )
|
326 |
wp_nonce_field('login-lockdown_release-lockdowns');
|
327 |
?>
|
328 |
-
<h3><?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
329 |
<?php
|
330 |
$num_lockedout = count($dalist);
|
331 |
if( 0 == $num_lockedout ) {
|
@@ -341,6 +385,7 @@ if ( function_exists('wp_nonce_field') )
|
|
341 |
<div class="submit">
|
342 |
<input type="submit" class="button button-primary" name="release_lockdowns" value="<?php _e('Release Selected', 'loginlockdown') ?>" /></div>
|
343 |
</form>
|
|
|
344 |
</div>
|
345 |
<?php
|
346 |
}//End function print_loginlockdownAdminPage()
|
@@ -455,7 +500,70 @@ if ( isset($loginlockdown_db_version) ) {
|
|
455 |
return $user;
|
456 |
}
|
457 |
endif;
|
458 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
459 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
460 |
|
461 |
-
?>
|
2 |
/*
|
3 |
Plugin Name: Login LockDown
|
4 |
Plugin URI: http://www.bad-neighborhood.com/
|
5 |
+
Version: v1.7.1
|
6 |
Author: Michael VanDeMar
|
7 |
Description: Adds some extra security to WordPress by restricting the rate at which failed logins can be re-attempted from a given IP range. Distributed through <a href="http://www.bad-neighborhood.com/" target="_blank">Bad Neighborhood</a>.
|
8 |
*/
|
10 |
/*
|
11 |
== Change Log ==
|
12 |
*
|
13 |
+
* ver. 1.7.1 13-Sep-2016
|
14 |
+
* - fixed bug causing all ipv6 addresses to get locked out if 1 was
|
15 |
+
* - added in WordPress MultiSite functionality
|
16 |
+
* - fixed bug where subnets could be overly matched, causing more IPs to be blocked than intended
|
17 |
+
* - moved the report for locked out IP addresses to its own tab
|
18 |
+
*
|
19 |
* ver. 1.6.1 8-Mar-2014
|
20 |
* - fixed html glitch preventing options from being saved
|
21 |
*
|
137 |
global $wpdb;
|
138 |
global $loginlockdownOptions;
|
139 |
$table_name = $wpdb->prefix . "login_fails";
|
140 |
+
$subnet = calc_subnet($_SERVER['REMOTE_ADDR']);
|
|
|
141 |
|
142 |
$numFailsquery = "SELECT COUNT(login_attempt_ID) FROM $table_name " .
|
143 |
"WHERE login_attempt_date + INTERVAL " .
|
144 |
$loginlockdownOptions['retries_within'] . " MINUTE > now() AND " .
|
145 |
"login_attempt_IP LIKE '%s'";
|
146 |
+
$numFailsquery = $wpdb->prepare( $numFailsquery, $subnet[1] . "%");
|
147 |
|
148 |
$numFails = $wpdb->get_var($numFailsquery);
|
149 |
return $numFails;
|
153 |
global $wpdb;
|
154 |
global $loginlockdownOptions;
|
155 |
$table_name = $wpdb->prefix . "login_fails";
|
156 |
+
$subnet = calc_subnet($_SERVER['REMOTE_ADDR']);
|
157 |
|
158 |
$username = sanitize_user($username);
|
159 |
$user = get_user_by('login',$username);
|
165 |
}
|
166 |
$insert = "INSERT INTO " . $table_name . " (user_id, login_attempt_date, login_attempt_IP) " .
|
167 |
"VALUES ('" . $user_id . "', now(), '%s')";
|
168 |
+
$insert = $wpdb->prepare( $insert, $subnet[0] );
|
169 |
$results = $wpdb->query($insert);
|
170 |
}
|
171 |
}
|
174 |
global $wpdb;
|
175 |
global $loginlockdownOptions;
|
176 |
$table_name = $wpdb->prefix . "lockdowns";
|
177 |
+
$subnet = calc_subnet($_SERVER['REMOTE_ADDR']);
|
178 |
|
179 |
$username = sanitize_user($username);
|
180 |
$user = get_user_by('login',$username);
|
187 |
$insert = "INSERT INTO " . $table_name . " (user_id, lockdown_date, release_date, lockdown_IP) " .
|
188 |
"VALUES ('" . $user_id . "', now(), date_add(now(), INTERVAL " .
|
189 |
$loginlockdownOptions['lockout_length'] . " MINUTE), '%s')";
|
190 |
+
$insert = $wpdb->prepare( $insert, $subnet[0] );
|
191 |
$results = $wpdb->query($insert);
|
192 |
}
|
193 |
}
|
195 |
function isLockedDown() {
|
196 |
global $wpdb;
|
197 |
$table_name = $wpdb->prefix . "lockdowns";
|
198 |
+
$subnet = calc_subnet($_SERVER['REMOTE_ADDR']);
|
|
|
199 |
|
200 |
$stillLockedquery = "SELECT user_id FROM $table_name " .
|
201 |
"WHERE release_date > now() AND " .
|
202 |
"lockdown_IP LIKE %s";
|
203 |
+
$stillLockedquery = $wpdb->prepare($stillLockedquery,$subnet[1] . "%");
|
204 |
|
205 |
$stillLocked = $wpdb->get_var($stillLockedquery);
|
206 |
|
236 |
return $loginlockdownAdminOptions;
|
237 |
}
|
238 |
|
239 |
+
function calc_subnet($ip) {
|
240 |
+
$subnet[0] = $ip;
|
241 |
+
if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
|
242 |
+
$ip = expandipv6($ip);
|
243 |
+
preg_match("/^([0-9abcdef]{1,4}:){4}/", $ip, $matches);
|
244 |
+
$subnet[0] = $ip;
|
245 |
+
$subnet[1] = $matches[0];
|
246 |
+
} else {
|
247 |
+
$subnet[1] = substr ($ip, 0 , strrpos ( $ip, "." ) + 1);
|
248 |
+
}
|
249 |
+
return $subnet;
|
250 |
+
}
|
251 |
+
|
252 |
+
function expandipv6($ip){
|
253 |
+
$hex = unpack("H*hex", inet_pton($ip));
|
254 |
+
$ip = substr(preg_replace("/([A-f0-9]{4})/", "$1:", $hex['hex']), 0, -1);
|
255 |
+
|
256 |
+
return $ip;
|
257 |
+
}
|
258 |
+
|
259 |
+
|
260 |
function print_loginlockdownAdminPage() {
|
261 |
global $wpdb;
|
262 |
$table_name = $wpdb->prefix . "lockdowns";
|
312 |
$dalist = listLockedDown();
|
313 |
?>
|
314 |
<div class="wrap">
|
315 |
+
<?php
|
316 |
+
|
317 |
+
$active_tab = isset( $_GET[ 'tab' ] ) ? $_GET[ 'tab' ] : 'settings';
|
318 |
+
|
319 |
+
?>
|
320 |
+
<h2><?php _e('Login LockDown Options', 'loginlockdown') ?></h2>
|
321 |
+
|
322 |
+
<h2 class="nav-tab-wrapper">
|
323 |
+
<a href="?page=loginlockdown.php&tab=settings" class="nav-tab <?php echo $active_tab == 'settings' ? 'nav-tab-active' : ''; ?>">Settings</a>
|
324 |
+
<a href="?page=loginlockdown.php&tab=activity" class="nav-tab <?php echo $active_tab == 'activity' ? 'nav-tab-active' : ''; ?>">Activity (<?php echo count($dalist); ?>)</a>
|
325 |
+
</h2>
|
326 |
+
<?php if ( $active_tab == 'settings' ) { ?>
|
327 |
<form method="post" action="<?php echo esc_attr($_SERVER["REQUEST_URI"]); ?>">
|
328 |
<?php
|
329 |
if ( function_exists('wp_nonce_field') )
|
330 |
wp_nonce_field('login-lockdown_update-options');
|
331 |
?>
|
332 |
+
|
333 |
<h3><?php _e('Max Login Retries', 'loginlockdown') ?></h3>
|
334 |
<p>Number of failed login attempts within the "Retry Time Period Restriction" (defined below) needed to trigger a LockDown.</p>
|
335 |
<p><input type="text" name="ll_max_login_retries" size="8" value="<?php echo esc_attr($loginlockdownAdminOptions['max_login_retries']); ?>"></p>
|
356 |
<div class="submit">
|
357 |
<input type="submit" class="button button-primary" name="update_loginlockdownSettings" value="<?php _e('Update Settings', 'loginlockdown') ?>" /></div>
|
358 |
</form>
|
359 |
+
<?php } else { ?>
|
360 |
<form method="post" action="<?php echo esc_attr($_SERVER["REQUEST_URI"]); ?>">
|
361 |
<?php
|
362 |
if ( function_exists('wp_nonce_field') )
|
363 |
wp_nonce_field('login-lockdown_release-lockdowns');
|
364 |
?>
|
365 |
+
<h3><?php
|
366 |
+
if( count($dalist) == 1 ) {
|
367 |
+
printf( esc_html__( 'There is currently %d locked out IP address.', 'loginlockdown' ), count($dalist) );
|
368 |
+
|
369 |
+
} else {
|
370 |
+
printf( esc_html__( 'There are currently %d locked out IP addresses.', 'loginlockdown' ), count($dalist) );
|
371 |
+
} ?></h3>
|
372 |
+
|
373 |
<?php
|
374 |
$num_lockedout = count($dalist);
|
375 |
if( 0 == $num_lockedout ) {
|
385 |
<div class="submit">
|
386 |
<input type="submit" class="button button-primary" name="release_lockdowns" value="<?php _e('Release Selected', 'loginlockdown') ?>" /></div>
|
387 |
</form>
|
388 |
+
<?php } ?>
|
389 |
</div>
|
390 |
<?php
|
391 |
}//End function print_loginlockdownAdminPage()
|
500 |
return $user;
|
501 |
}
|
502 |
endif;
|
503 |
+
// multisite network-wide activation
|
504 |
+
register_activation_hook( __FILE__, 'loginlockdown_multisite_activate' );
|
505 |
+
function loginlockdown_multisite_activate($networkwide) {
|
506 |
+
global $wpdb;
|
507 |
+
|
508 |
+
if (function_exists('is_multisite') && is_multisite()) {
|
509 |
+
// check if it is a network activation - if so, run the activation function for each blog id
|
510 |
+
if ($networkwide) {
|
511 |
+
$old_blog = $wpdb->blogid;
|
512 |
+
// Get all blog ids
|
513 |
+
$blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
|
514 |
+
foreach ($blogids as $blog_id) {
|
515 |
+
switch_to_blog($blog_id);
|
516 |
+
loginLockdown_install();
|
517 |
+
}
|
518 |
+
switch_to_blog($old_blog);
|
519 |
+
return;
|
520 |
+
}
|
521 |
+
}
|
522 |
+
}
|
523 |
|
524 |
+
// multisite new site activation
|
525 |
+
add_action( 'wpmu_new_blog', 'loginlockdown_multisite_newsite', 10, 6);
|
526 |
+
function loginlockdown_multisite_newsite($blog_id, $user_id, $domain, $path, $site_id, $meta ) {
|
527 |
+
global $wpdb;
|
528 |
+
|
529 |
+
if (is_plugin_active_for_network('loginlockdown/loginlockdown.php')) {
|
530 |
+
$old_blog = $wpdb->blogid;
|
531 |
+
switch_to_blog($blog_id);
|
532 |
+
loginLockdown_install();
|
533 |
+
switch_to_blog($old_blog);
|
534 |
+
}
|
535 |
+
}
|
536 |
+
|
537 |
+
// multisite old sites check
|
538 |
+
|
539 |
+
add_action('admin_init','loginlockdown_multisite_legacy');
|
540 |
+
function loginlockdown_multisite_legacy() {
|
541 |
+
$loginlockdownMSRunOnce = get_option("loginlockdownmsrunonce");
|
542 |
+
if ( empty($loginlockdownMSRunOnce) ) {
|
543 |
+
global $wpdb;
|
544 |
+
|
545 |
+
if (function_exists('is_multisite') && is_multisite()) {
|
546 |
+
|
547 |
+
$old_blog = $wpdb->blogid;
|
548 |
+
|
549 |
+
// Get all blog ids
|
550 |
+
$blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
|
551 |
+
foreach ($blogids as $blog_id) {
|
552 |
+
|
553 |
+
// check if already exists
|
554 |
+
$bed_check = $wpdb->query("SHOW TABLES LIKE '{$wpdb->base_prefix}{$blog_id}_login_fails'");
|
555 |
+
if (!$bed_check) {
|
556 |
+
|
557 |
+
switch_to_blog($blog_id);
|
558 |
+
loginLockdown_install();
|
559 |
+
|
560 |
+
}
|
561 |
+
}
|
562 |
+
switch_to_blog($old_blog);
|
563 |
+
}
|
564 |
+
add_option("loginlockdownmsrunonce", "done", "", "no");
|
565 |
+
return;
|
566 |
+
}
|
567 |
+
}
|
568 |
+
}
|
569 |
|
|
readme.txt
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
=== Login LockDown ===
|
2 |
Developer: Michael VanDeMar (michael@endlesspoetry.com)
|
3 |
-
Tags: security, login
|
4 |
Requires at least: 3.6
|
5 |
-
Tested up to: 4.
|
6 |
-
Stable Tag: 1.
|
7 |
|
8 |
Limits the number of login attempts from a given IP range within a certain time period.
|
9 |
|
@@ -14,7 +14,7 @@ certain number of attempts are detected within a short period of time from the s
|
|
14 |
IP range, then the login function is disabled for all requests from that range.
|
15 |
This helps to prevent brute force password discovery. Currently the plugin defaults
|
16 |
to a 1 hour lock out of an IP block after 3 failed login attempts within 5 minutes. This can be modified
|
17 |
-
via the Options panel.
|
18 |
|
19 |
== Installation ==
|
20 |
|
@@ -26,6 +26,13 @@ Enjoy.
|
|
26 |
|
27 |
== Change Log ==
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
ver. 1.6.1 8-Mar-2014
|
30 |
|
31 |
- fixed html glitch preventing options from being saved
|
1 |
=== Login LockDown ===
|
2 |
Developer: Michael VanDeMar (michael@endlesspoetry.com)
|
3 |
+
Tags: security, login, login form
|
4 |
Requires at least: 3.6
|
5 |
+
Tested up to: 4.9.6
|
6 |
+
Stable Tag: 1.7.1
|
7 |
|
8 |
Limits the number of login attempts from a given IP range within a certain time period.
|
9 |
|
14 |
IP range, then the login function is disabled for all requests from that range.
|
15 |
This helps to prevent brute force password discovery. Currently the plugin defaults
|
16 |
to a 1 hour lock out of an IP block after 3 failed login attempts within 5 minutes. This can be modified
|
17 |
+
via the Options panel. Administrators can release locked out IP ranges manually from the panel.
|
18 |
|
19 |
== Installation ==
|
20 |
|
26 |
|
27 |
== Change Log ==
|
28 |
|
29 |
+
ver. 1.7.1 13-Sep-2016
|
30 |
+
|
31 |
+
- fixed bug causing all ipv6 addresses to get locked out if 1 was
|
32 |
+
- added in WordPress MultiSite functionality
|
33 |
+
- fixed bug where subnets could be overly matched, causing more IPs to be blocked than intended
|
34 |
+
- moved the report for locked out IP addresses to its own tab
|
35 |
+
|
36 |
ver. 1.6.1 8-Mar-2014
|
37 |
|
38 |
- fixed html glitch preventing options from being saved
|
version.txt
CHANGED
@@ -1 +1 @@
|
|
1 |
-
1.
|
1 |
+
1.7.1
|