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"; } ?>
Leave a Reply