Показывать капчу при обнаружении неожиданной навигации, чтобы предотвратить злоупотребление трафиком


Я заметил, что некоторые пользователи перегружают мой веб-сайт, загружая несколько файлов (например, 500 файлов одновременно) и открывая больше страниц за небольшую продолжительность, я хочу показать капчу , если пользователь обнаружит неожиданную навигацию.

Я знаю, как реализовать Капчу , но я не могу понять, каков наилучший подход для обнаружения злоупотреблений трафиком с использованием (PHP)?

Author: akirk, 2013-04-16

3 answers

Общий подход заключается в использовании чего-то вроде memcached для хранения запросов на минутной основе, у меня есть небольшой класс с открытым исходным кодом, который достигает этого: php-ratelimiter

Если вас интересует более подробное объяснение того, почему запросы должны храниться на минутной основе, проверьте это сообщение.

Итак, подводя итог, ваш код может выглядеть следующим образом:

if (!verifyCaptcha()) {
    $rateLimiter = new RateLimiter(new Memcache(), $_SERVER["REMOTE_ADDR"]);
    try {
        $rateLimiter->limitRequestsInMinutes(100, 5);
    } catch (RateExceededException $e) {
        displayCaptcha();
        exit;
    }
}

На самом деле, код основан на поминутной основе, но вы можете довольно легко адаптируйте это так, чтобы это происходило каждые 30 секунд:

private function getKeys($halfminutes) {
    $keys = array();
    $now = time();
    for ($time = $now - $halfminutes * 30; $time <= $now; $time += 30) {
        $keys[] = $this->prefix . date("dHis", $time);
    }
    return $keys;
}
 5
Author: akirk, 2013-04-19 08:54:46

Введение

На аналогичный вопрос был дан ответ до Предотвращение затопления PHP-скрипта , но это может быть недостаточной причиной:

  • Он использует $_SERVER["REMOTE_ADDR"], и они являются некоторым общим соединением, имеют одинаковое Public IP Address
  • Существует так много Firefox addon, что can позволяет пользователям использовать несколько прокси-серверов для каждого запроса

Многократный запрос! = Многократная загрузка

Предотвращение множественного запроса полностью отличается от многократной загрузки почему?

Чтобы не представить файл 10MB, для загрузки которого потребуется 1min, если вы ограничите пользователей, чтобы сказать 100 request per min, что это означает, что вам предоставлен доступ к пользователю для загрузки

10MB * 100 per min

Чтобы устранить эту проблему, вы можете посмотреть Загрузка - максимальное количество подключений на пользователя?.

Множественный запрос

Вернуться к доступу к странице вы можете использовать SimpleFlood, которые расширяют memcache, чтобы ограничить количество пользователей в секунду. Он использует cookies для разрешения общей проблема с подключением и попытки получить реальный IP-адрес

$flood = new SimpleFlood();
$flood->addserver("127.0.0.1"); // add memcache server
$flood->setLimit(2); // expect 1 request every 2 sec
try {
    $flood->check();
} catch ( Exception $e ) {
    sleep(2); // Feel like wasting time 
    // Display Captcher
    // Write Message to Log
    printf("%s => %s %s", date("Y-m-d g:i:s"), $e->getMessage(), $e->getFile());
}

Пожалуйста, обратите внимание, что SimpleFlood::setLimit(float $float); принимает поплавки, поэтому у вас может быть

$flood->setLimit(0.1); // expect 1 request every 0.1 sec

Используемый класс

class SimpleFlood extends \Memcache {
    private $ip;
    private $key;
    private $prenalty = 0;
    private $limit = 100;
    private $mins = 1;
    private $salt = "I like TO dance A #### Lot";

    function check() {
        $this->parseValues();
        $runtime = floatval($this->get($this->key));
        $diff = microtime(true) - $runtime;
        if ($diff < $this->limit) {
            throw new Exception("Limit Exceeded By :  $this->ip");
        }
        $this->set($this->key, microtime(true));
    }

    public function setLimit($limit) {
        $this->limit = $limit;
    }

    private function parseValues() {
        $this->ip = $this->getIPAddress();
        if (! $this->ip) {
            throw new Exception("Where the hell is the ip address");
        }

        if (isset($_COOKIE["xf"])) {
            $cookie = json_decode($_COOKIE["xf"]);
            if ($this->ip != $cookie->ip) {
                unset($_COOKIE["xf"]);
                setcookie("xf", null, time() - 3600);
                throw new Exception("Last IP did not match");
            }

            if ($cookie->hash != sha1($cookie->key . $this->salt)) {
                unset($_COOKIE["xf"]);
                setcookie("xf", null, time() - 3600);
                throw new Exception("Nice Faking cookie");
            }
            if (strpos($cookie->key, "floodIP") === 0) {
                $cookie->key = "floodRand" . bin2hex(mcrypt_create_iv(50, MCRYPT_DEV_URANDOM));
            }
            $this->key = $cookie->key;
        } else {
            $this->key = "floodIP" . sha1($this->ip);
            $cookie = (object) array(
                    "key" => $this->key,
                    "ip" => $this->ip
            );
        }
        $cookie->hash = sha1($this->key . $this->salt);
        $cookie = json_encode($cookie);
        setcookie("xf", $cookie, time() + 3600); // expire in 1hr
    }

    private function getIPAddress() {
        foreach ( array(
                'HTTP_CLIENT_IP',
                'HTTP_X_FORWARDED_FOR',
                'HTTP_X_FORWARDED',
                'HTTP_X_CLUSTER_CLIENT_IP',
                'HTTP_FORWARDED_FOR',
                'HTTP_FORWARDED',
                'REMOTE_ADDR'
        ) as $key ) {
            if (array_key_exists($key, $_SERVER) === true) {
                foreach ( explode(',', $_SERVER[$key]) as $ip ) {
                    if (filter_var($ip, FILTER_VALIDATE_IP) !== false) {
                        return $ip;
                    }
                }
            }
        }

        return false;
    }
}

Заключение

Это базовое доказательство концепции, и к нему могут быть добавлены дополнительные слои, такие как

  • Установите другой предел для разных URL-адресов
  • Добавьте поддержку штрафов, когда вы блокируете пользователя на определенное количество минут или часов
  • Обнаружение и Другой предел для Tor соединений
  • и т.д.
 2
Author: Baba, 2017-05-23 12:18:55

Я думаю, что в этом случае вы можете использовать сеансы. Инициализируйте сеанс, чтобы сохранить метку времени [используйте microtime для достижения лучших результатов], а затем получите метку времени новой страницы.Разница может быть использована для анализа частоты посещаемых страниц и отображения капчи.

Вы также можете запустить счетчик посещаемых страниц и использовать 2d-массив для хранения страницы и метки времени.Если значение посещаемых страниц внезапно увеличивается, вы можете проверить разницу во времени.

 1
Author: Sudo Reboot, 2013-04-21 16:56:41