It's almost futile to try to block IP addresses, simply because they change frequently - even for fixed landline ISPs - and it's trivial for a troublemaker to use TOR, VPN, or proxy to hide their real IP.
I found a way to block registrations and logins from anyone hiding behind a TOR address, or a Proxy - which blocked virtually all troublemakers - however, there were a few legitimate people who complained because this also blocks VPN (which uses proxies). So there is a trade off. Here's how we approached solving the problem on our forum:
The first step is to create a Task in ACP, which runs daily, which downloads a list of active TOR exit nodes to a text file - I think there are something like 1200 at any given time. Note, I created my script before recent changes by the TOR service - so I'm not sure if it still works (we've closed down our forum this winter), but you can see the Tor bulk exit list service here:
https://blog.torproject.org/changes-tor-...st-service
And this will download the current list:
https://check.torproject.org/torbulkexitlist
In ACP I created a Task which downloads the Tor list to the web server in a file called torexits.txt
function task_torexits($task)
{
$url = "https://check.torproject.org/torbulkexitlist";
$ch = curl_init();
$fp = fopen("../torexits.txt", "w");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_URL, $url);
curl_exec($ch);
curl_close($ch);
fclose($fp);
add_task_log($task, "Tor List Updated");
}
Now we have a locally stored list of Tor exits updated automatically daily. So to test visitors who try to register or log in, we add a script at the top of the members.php file to filter out anyone visiting from a Tor exit. I created this script which drops any TOR visitor out to an HTTP 404 Error page, and log it in a text file for testing. (The log file would be better stored in MySQL where it can be protected from someone accidentally finding it and potentially compromising forum privacy...). I'm not actually a programmer and I don't know if this is this is the best way to do it or not, but I got it to work by trial and many errors:
// Get visitor's IP address
$ipAddress = $_SERVER["REMOTE_ADDR"];
// Block visitor if IP is a TOR exit node, list updated daily via ACP Task
function isTor($ipTor){
$Torlist = explode("\n", file_get_contents('torexits.txt'));
if(in_array($ipTor, $Torlist))
return true;
}
if (isTor($ipAddress)) {
$ip2string = date("Y-m-d H:i:s") . "\t" . $ipAddress . "\tTOR" . "\n";
file_put_contents('torlog.txt', $ip2string, FILE_APPEND);
header("HTTP/1.1 404 Not Found");
header("Location: 404.php");
exit;
}
Even after the above we still had enough problematic registrations from users hiding behind VPN and proxy servers, so I subscribed to the IP2Location.com web service (I have no affiliation), which has a constantly updated list of active proxy exits you can query with JSON. You have to subscribe, and it costs about $50 for 10,000 queries - but since we blocked out TOR for free, this was a reasonable cost. You can set up a trial subscription - it works by embedding your subscription or trial code in a script, shown below.
https://www.ip2location.com/web-service/ip2proxy
So we added this script in members.php, just under the TOR script above:
It queries the Visitor's IP against IP2Location's Proxy database using JSON and drops them out to a 404 error page and logs the attempt to a text file, if either of these conditions are true: The visitor is using a known proxy, or, the visitor's IP is from a country you want to block, using a list of 2-letter ISO country codes, (ie, 'us', 'uk'):
// Check Visitor against IP2Location Proxy database
if(isset($ipAddress)) {
// Check IP with IP2Location Proxy database
$urlTemplate = 'https://api.ip2proxy.com/?ip=' . $ipAddress .
'&key=YOURKEYHERE&package=PX1';
$urlToCall = sprintf( $urlTemplate, $ipAddress);
$rawJson = file_get_contents( $urlToCall );
$ip2location = json_decode( $rawJson, true );
//Test response from to IP2Location
if( $ip2location['response']=="OK" ){
// Block Visitor if using a Proxy
if( $ip2location['isProxy']=="YES" ){
$ip2string = date("Y-m-d H:i:s") . "\t" . $ipAddress .
"\tProxy\t" . $ip2location['countryCode'] . "\t" .
$ip2location['countryName'] . "\n";
file_put_contents('iplog.txt', $ip2string, FILE_APPEND);
header("HTTP/1.1 404 Not Found");
header("Location: 404.php");
exit;
}
// Block Visitor if from a blocked country
$blockCountry = array( 'RU', 'KP');
if( in_array ( $ip2location['countryCode'] , $blockCountry , true )){
$ip2string = date("Y-m-d H:i:s") . "\t" . $ipAddress .
"\tBlock\t" . $ip2location['countryCode'] . "\t" .
$ip2location['countryName'] . "\n" ;
file_put_contents('iplog.txt', $ip2string, FILE_APPEND);
header("HTTP/1.1 404 Not Found");
header("Location: 404.php");
exit;
}
$ip2string = date("Y-m-d H:i:s") . "\t" . $ipAddress .
"\tOK\t" . $ip2location['countryCode'] . "\t" .
$ip2location['countryName'] . "\n" ;
file_put_contents('iplog.txt', $ip2string, FILE_APPEND);
}
}
Since these scripts only run when a person actually tries to registor or log in - activating the members.php file - the volume of hits was relatively low on our forum, and we had no problem on a shared server at a standard hosting company. And again - a word of caution - the text log file should only be used for testing, and if you want a proper log the script should be enhanced to store it in MySQL...
Finally, anyone who successfully registered - and MyBB put them in the "Registered" group - we modified the group settings in ACP to hold the first post for moderation. Once approved, the ACP would automatically promote the user to an "Approved" group where they could then post normally. Collectively, the above steps kept out 99.9% of bad actors for several years, it was a breeze to moderate.