Rate Limiting admin-ajax.php

File untuk berinteraksi dengan metode POST di wordpress adalah file admin-ajax.php, yang terletak di dalam folder /wp-admin/admin-ajax.php. File ini sangat penting akan tetapi bisa menjadi bumerang jika file ini diserang oleh DDoS atau scraper, karenanya perlu untuk dilakukan rate limit. Bagaimana caranya?

Pertama, kita jadikan segala akses ke /wp-admin/admin-ajax.php dieksekusi server sebagai /admin-ajax-rate-limited.php, menggunakan rewrite rule

Tambahkan baris ini di .htaccess Anda

RewriteRule ^wp-admin/admin-ajax.php admin-ajax-rate-limiting.php

Berikutnya, buat database untuk menampung data clients IP dan hits yang dilakukan clients

DROP TABLE IF EXISTS `clients`;
CREATE TABLE `clients` (
  `id` int(11) NOT NULL,
  `ip` char(64) NOT NULL,
  `hitcount` int(11) NOT NULL,
  `firsthit` double NOT NULL,
  `lasthit` double NOT NULL,
  `blocked` int(1) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

DROP TABLE IF EXISTS `hits`;
CREATE TABLE `hits` (
  `id` int(11) NOT NULL,
  `ip` char(64) NOT NULL,
  `hittime` double NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

ALTER TABLE `clients`
  ADD UNIQUE KEY `id` (`id`);

ALTER TABLE `hits`
  ADD UNIQUE KEY `id` (`id`);

ALTER TABLE `clients`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;

ALTER TABLE `hits`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;

Berikutnya, buat file bernama admin-ajax-rate-limiting-db.php dan buat file bernama admin-ajax-rate-limiting.php di public_html (satu tingkat sebelum wp-admin)

Untuk yang DB, isikan begini:

<?php
$dbhost = "";
$dbuser = "";
$dbname = "";
$dbpass = "";
?>

Isikan konfigurasi DB Anda di sana. Untuk yang rate-limitingnya,

<?php
include "admin-ajax-rate-limiting-db.php";
$rlconn = mysqli_connect($dbhost,$dbuser,$dbpass,$dbname);

$clientIP = $_SERVER['REMOTE_ADDR'];
$referer = $_SERVER['HTTP_REFERER'];
$startTime = microtime(true);
$nowTime = microtime(true);
$maxHit = 3;
$inSec = 10;
$blockTime = 60;
$intervalLimit = $nowTime - $inSec;
$blockLimit = $nowTime - $blockTime;

// Cek kalau dari WP-Admin jangan block, langsung return admin-ajax
if(strpos($referer, "/wp-admin/") > 0){
	chdir("wp-admin");
	include "admin-ajax.php";
	return 0;
}

// cleanup Yang Blocked
$rlCleanupSQL = "DELETE FROM `clients` WHERE `lasthit` <= '$blockLimit'";
$rlCleanupResult = mysqli_query($rlconn, $rlCleanupSQL);
$rlCleanupSQL = "DELETE FROM `hits` WHERE `hittime` <= '$blockLimit'";
$rlCleanupResult = mysqli_query($rlconn, $rlCleanupSQL);

// Get Clients Data
$rlSql = "SELECT * FROM `clients` WHERE `ip` = '$clientIP'";
$rlResult = mysqli_query($rlconn, $rlSql);
$rlRowCount = mysqli_num_rows($rlResult);
$rlRow = mysqli_fetch_assoc($rlResult);

// Get Clients Log
$rlSql = "SELECT * FROM `hits` WHERE `ip` = '$clientIP' AND `hittime` >= $intervalLimit AND `hittime` <= $nowTime";
$rlResult = mysqli_query($rlconn, $rlSql);
$rlLogCount = mysqli_num_rows($rlResult);

if($rlRowCount == 0){
	$rlInsertSQL = "INSERT INTO `clients` VALUES (null, '$clientIP', '1', '$nowTime', '$nowTime','0')";
	$rlInsertResult = mysqli_query($rlconn, $rlInsertSQL);
	$rlInsertSQL = "INSERT INTO `hits` VALUES (null, '$clientIP', '$nowTime')";
	$rlInsertResult = mysqli_query($rlconn, $rlInsertSQL);
	$endTime = microtime(true);
	$processTime = $endTime - $startTime;
	echo "Logged in $processTime seconds\n";
}else{
	$id = $rlRow['id'];
	$ip = $rlRow['ip'];
	$hitCount = $rlRow['hitcount'];
	$firstHit = $rlRow['firsthit'];
	$lastHit = $rlRow['lasthit'];
	$blocked = $rlRow['blocked'];
	$interval = $lastHit - $firstHit;
	if($blocked == 1){
		$endTime = microtime(true);
		$processTime = $endTime - $startTime;
		echo "Rate Limited! (1)\n";
		echo "Blocked in $processTime seconds\n";
		return 0;	
	}elseif($rlLogCount >= $maxHit){
		$rlUpdateSQL = "UPDATE `clients` SET `blocked` = '1', `lasthit` = '$nowTime' WHERE `ip` = '$clientIP'";
		$rlUpdateResult = mysqli_query($rlconn, $rlUpdateSQL);
		$endTime = microtime(true);
		echo "Rate Limited! (2)\n";
		echo "Blocked in $processTime seconds\n";
		return 0;	
	}else{
		$newHit = $hitCount + 1;
		$rlUpdateSQL = "UPDATE `clients` SET `hitcount` = '$newHit', `lasthit` = '$nowTime' WHERE `ip` = '$clientIP'";
		$rlUpdateResult = mysqli_query($rlconn, $rlUpdateSQL);
		$rlInsertSQL = "INSERT INTO `hits` VALUES(null, '$clientIP', '$nowTime')";
		$rlInsertResult = mysqli_query($rlconn, $rlInsertSQL);
		$endTime = microtime(true);
		$processTime = $endTime - $startTime;
		echo "Logged in $processTime seconds\n";
	}
}
mysqli_close($rlconn);
if($rlRowCount == 0 or $blocked == 0){
	chdir("wp-admin");
	include "admin-ajax.php";
}
?>

 


Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *