I wanted to create a simple drop-in script to add brute-force attempt blocking by IP address to my PHP/MySQL login scripts. It should be pretty simple to use. It needs a database to run off, you enter the database values and call the script (see usage) before login and on login failure (also before login processing in case the login form variables are sent without using the actual login page). Code follows (watch out for line-wrapping!):
<?php
/*
COPYRIGHT: www.cheesefather.com
FILE VERSION 1.0 30/10/2011
*/
/*
USAGE:
# BEFORE LOGIN ATTEMPT - CHECK IF IP BLOCKED
include('ip_login.php');
if (checkIP($_SERVER['REMOTE_ADDR'],'check')!=1) die('too many login failures, you are temporarily blocked'); //user is blocked
# IF LOGIN FAILS - ADD FAILURE TO DATABASE
checkIP($_SERVER['REMOTE_ADDR'],'add');
# TO DEBUG SCRIPT
ip_login.php?debug=1
# EXPLANATION OF VALUES
if an ip address fails login within $grace_period_secs seconds of a previous failure, the number of failures is increased in the database
when $num_fails failed attempts is reached, the ip address is blocked for a period of $block_period_secs seconds before it can try again
*/
# FUNCTION TO CHECK THE LOGIN IP
function checkIP($ip,$action) {
# DATABASE CONNECTION - CHANGE THESE VALUES TO MATCH YOUR CONFIGURATION
$db_host = 'localhost';
$db_name = '';
$db_user = '';
$db_pass = '';
$num_fails = 5; //maximum value is 127
$grace_period_secs = 300; //300 seconds is 5 minutes
$block_period_secs = 3600; //3600 seconds is 60 minutes
/* YOU DO NOT NEED TO EDIT BELOW THIS LINE */
$output = ''; //for debug
$db_table = 'ip_login';
# CHECK DB CONNECTION DEFINED
if ($db_host == '' || $db_name == '' || $db_user == '' || $db_pass == '') die('please enter the database connection information - ERROR'); //this should cause your logins to fail
# CHECK DB CONNECTION WORKS
$connection = mysql_connect($db_host, $db_user, $db_pass) or die('cannot connect to database - ERROR ('.mysql_error().')'); //this should cause your logins to fail
# CREATE THE TABLE IF IT DOES NOT EXIST
mysql_select_db($db_name); //select database
$check_table = mysql_query("SHOW TABLES FROM ".$db_name." LIKE 'ip_login'",$connection);
if (mysql_num_rows($check_table)<1) {
$output .= 'table ('.$db_table.") does not exist - WARNING<br />\n";
if ($create_table = mysql_query("CREATE TABLE IF NOT EXISTS `ip_login` (`id` int(6) NOT NULL auto_increment,`ip_address` varchar(15) NOT NULL,`num_fails` tinyint(3) NOT NULL,`timestamp` varchar(10) NOT NULL,PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Failed login IP database' AUTO_INCREMENT=1",$connection)) $output .= 'table ('.$db_table.") created - OK<br />\n";
else $output .= 'table ('.$db_table.') not created - ERROR ('.mysql_error().")<br />\n";
} //create table
else $output .= 'table ('.$db_table.") exists - OK<br />\n"; //table exists
# ADD IP TO DATABASE
if ($action == 'add') {
$check_ip = mysql_query("SELECT timestamp FROM ".$db_table." WHERE ip_address = '".$ip."'", $connection);
if (mysql_num_rows($check_ip)>0) {
$last_timestamp = mysql_fetch_array($check_ip);
if ($last_timestamp >= (time() - $grace_period_secs)) $increment_ip = mysql_query("UPDATE ".$db_table." SET num_fails = num_fails+1 WHERE ip_address = '".$ip."'", $connection);
} //ip already in database, add failure if within grace period
else $add_ip = mysql_query("INSERT INTO ".$db_table." (ip_address,num_fails,timestamp) VALUES ('".$ip."','1','".time()."')",$connection);
$return = 1;
} //if adding ip address
# CLEAN UP OLD LOGIN ATTEMPTS
$delete_ips = mysql_query("DELETE FROM ".$db_table." WHERE timestamp < '". (time() - $block_period_secs) ."'", $connection);
# CHECK IF IP BLOCKED
if ($action == 'check') {
$check_ip = mysql_query("SELECT timestamp FROM ".$db_table." WHERE ip_address = '".$ip."' AND num_fails >= '".$num_fails."'", $connection);
if (mysql_num_rows($check_ip)>0) {
$last_timestamp = mysql_fetch_array($check_ip);
if ($last_timestamp >= (time() - $block_period_secs)) $return = 0; //still blocked
else $return = 1; //no longer blocked (should have been deleted above)
} //if ip in database
else $return = 1; //not blocked
} //if checking ip address
# ECHO OUTPUT IF DEBUG SET
if (isset($_GET['debug'])) echo $output;
return $return;
} //function
# RUN FUNCTION IF DEBUGGING
if (isset($_GET['debug'])) checkIP($_SERVER['REMOTE_ADDR'],'check');
?>