Skip to content

Commit cd8d34b

Browse files
committed
use cookies to flag browsers/IPs as poisoned
1 parent c7c5bb5 commit cd8d34b

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

incl/api.incl.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
*/
3030
]);
3131
define('API_ENCRYPTION_KEY', 'For TUJ Use Only');
32+
define('POISONED_IS_BANNED', false);
33+
define('POISON_CACHE_KEY', 'poisoned');
34+
define('POISON_COOKIE_NAME', 'koala');
35+
define('POISON_DURATION', 24 * 60 * 60);
36+
define('POISON_LOG_PATH', __DIR__ . '/../logs/poison.log');
3237

3338
if ((PHP_SAPI != 'cli') && (($inMaintenance = APIMaintenance()) !== false)) {
3439
header('HTTP/1.1 503 Service Unavailable');
@@ -578,6 +583,7 @@ function BotCheck($returnReason = false)
578583
$checked = $_SERVER['REMOTE_ADDR'];
579584
$reason = '';
580585
$banned = IPIsBanned($checked, $reason);
586+
$poisoned = PoisonCheck($checked);
581587

582588
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
583589
$filterOpts = array(
@@ -592,10 +598,17 @@ function BotCheck($returnReason = false)
592598
while (count($otherIPs) && !$banned) {
593599
if ($otherIP = filter_var(trim(array_shift($otherIPs)), FILTER_VALIDATE_IP, $filterOpts)) {
594600
$banned |= IPIsBanned($checked = $otherIP, $reason);
601+
$otherPoisoned = PoisonCheck($otherIP);
602+
$poisoned = $poisoned || $otherPoisoned;
595603
}
596604
}
597605
}
598606

607+
if (POISONED_IS_BANNED && !$banned && $poisoned) {
608+
$banned = true;
609+
$reason = 'ip';
610+
}
611+
599612
if ($returnReason) {
600613
return [
601614
'isbanned' => $banned,
@@ -781,6 +794,61 @@ function IPIsBanned($ip = false, &$result = '')
781794
return !!$result;
782795
}
783796

797+
/**
798+
* Returns true when the given IP from the current request is poisoned. May emit cookie headers.
799+
*
800+
* @param string $ip
801+
* @return bool
802+
*/
803+
function PoisonCheck($ip) {
804+
$cacheKey = POISON_CACHE_KEY . "_{$ip}";
805+
806+
$poisonedVia = MCGet($cacheKey);
807+
// Have we flagged this IP as poisoned internally?
808+
if ($poisonedVia === false) {
809+
// We haven't. Does it think that it's poisoned?
810+
if (isset($_COOKIE[POISON_COOKIE_NAME])) {
811+
// It says it is poisoned. Flag it on our end.
812+
FlagAsPoisoned($ip, true, $poisonedVia = substr($_COOKIE[POISON_COOKIE_NAME], 0, 80));
813+
}
814+
}
815+
816+
if ($poisonedVia) {
817+
setcookie(POISON_COOKIE_NAME, $poisonedVia, time() + POISON_DURATION, '/api/', '', true, true);
818+
}
819+
820+
return !!$poisonedVia;
821+
}
822+
823+
/**
824+
* Flags an IP as poisoned (or not), and logs it.
825+
*
826+
* @param string $ip
827+
* @param bool $isPoisoned
828+
* @param string $fromIp
829+
*/
830+
function FlagAsPoisoned($ip, $isPoisoned, $fromIp = '') {
831+
$cacheKey = POISON_CACHE_KEY . "_{$ip}";
832+
833+
if ($isPoisoned) {
834+
MCSet($cacheKey, $fromIp ?: $ip, POISON_DURATION);
835+
} else {
836+
MCDelete($cacheKey);
837+
}
838+
839+
file_put_contents(
840+
POISON_LOG_PATH,
841+
sprintf(
842+
"%s # %s Flagged as %spoisoned via %s\n",
843+
$ip,
844+
date('Y-m-d H:i:s'),
845+
$isPoisoned ? '' : 'NOT ',
846+
$fromIp ?: '?'
847+
),
848+
FILE_APPEND | LOCK_EX
849+
);
850+
}
851+
784852
function CaptchaDetails()
785853
{
786854
global $db;

scripts/poisonip.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
require_once(__DIR__.'/../incl/incl.php');
4+
require_once(__DIR__.'/../incl/api.incl.php');
5+
6+
if (!isset($argv[1])) {
7+
DebugMessage("Enter IP to poison on command line.\n");
8+
exit(1);
9+
}
10+
$ip = trim($argv[1]);
11+
12+
FlagAsPoisoned($ip, true);
13+
DebugMessage(sprintf("%s is poisoned.", $ip));

0 commit comments

Comments
 (0)