Счётчик запросов
Класс Throttler предоставляет очень простой способ ограничения количества попыток выполнения действия в определенный период времени. Он чаще всего используется для ограничения скорости работы API или ограничения количества попыток пользователя на форме, чтобы предотвратить атаки методом перебора. Сам класс может быть использован для любой операции, которую нужно ограничивать по действиям в заданном интервале времени.
Обзор
Throttler реализует упрощенную версию алгоритма Token Bucket. В сущности, каждое действие, которое вы хотите ограничить, рассматривается как ведро. Когда вы вызываете метод check(), вы указываете размер ведра, количество токенов, которые оно может содержать, и интервал времени. Каждый вызов check() использует 1 доступный токен по умолчанию. Давайте рассмотрим пример, чтобы прояснить это.
Допустим, мы хотим, чтобы действие происходило один раз в секунду. Первый вызов Throttler будет выглядеть следующим образом. Первый параметр - имя ведра, второй параметр - количество токенов, которые ведро может содержать, а третий - время, за которое ведро заполняется:
$throttler = \Config\Services::throttler(); $throttler->check($name, 60, MINUTE);
Здесь мы используем одну из глобальных констант для времени, чтобы сделать её более читаемой. Это означает, что ведро позволяет выполнить 60 действий в минуту или 1 действие в секунду.
Предположим, что сторонний скрипт пытается неоднократно обращаться к URL. Сначала он сможет использовать все 60 токенов менее чем за секунду. Однако после этого Throttler будет разрешать только одно действие в секунду, потенциально замедляя запросы достаточно, чтобы атака больше не была выгодна.
Примечание
Для работы класса Throttler необходимо настроить библиотеку кэша на использование обработчика, отличного от dummy. Для лучшей производительности рекомендуется использовать кэш в оперативной памяти, например, Redis или Memcached.
Ограничение скорости
Класс Throttler сам по себе не выполняет ограничение скорости или регулирование запросов, но является ключом к их работе. Предоставляется пример фильтра, который реализует очень простое ограничение скорости - один запрос в секунду на IP-адрес. Здесь мы рассмотрим, как он работает, как его можно настроить и начать использовать в вашем приложении.
Код
Вы можете создать свой собственный фильтр Throttler в файле app/Filters/Throttle.php, примерно так:
<?php
namespace App\Filters;
use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Config\Services;
class Throttle implements FilterInterface
{
/**
* This is a demo implementation of using the Throttler class
* to implement rate limiting for your application.
*
* @param array|null $arguments
*
* @return mixed
*/
public function before(RequestInterface $request, $arguments = null)
{
$throttler = Services::throttler();
// Restrict an IP address to no more than 1 request
// per second across the entire site.
if ($throttler->check(md5($request->getIPAddress()), 60, MINUTE) === false) {
return Services::response()->setStatusCode(429);
}
}
/**
* We don't have anything to do here.
*
* @param array|null $arguments
*
* @return mixed
*/
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
// ...
}
}
При выполнении этот метод сначала получает экземпляр счётчика запросов. Затем он использует IP-адрес в качестве имени ведра и настраивает ограничения на один запрос в секунду. Если счётчик запросов отклоняет проверку, возвращая false, то мы возвращаем ответ со статусом 429 - Слишком много попыток, и выполнение скрипта завершается до того, как оно дойдёт до контроллера. Этот пример будет ограничивать скорость на основе одного IP-адреса для всех запросов на сайт, а не для каждой страницы.
Применение фильтра
Нам не обязательно ограничивать скорость каждой страницы на сайте. Для многих веб-приложений наиболее целесообразно применять его только к POST-запросам, хотя API могут захотеть ограничить каждый запрос, сделанный пользователем. Для применения этого к входящим запросам необходимо отредактировать файл /app/Config/Filters.php и сначала добавить псевдоним к фильтру:
public $aliases = [
...
'throttle' => \App\Filters\Throttle::class,
];
Затем назначить его всем POST-запросам на сайте:
public $methods = [
'post' => ['throttle', 'csrf'],
];
И на этом всё. Теперь все POST-запросы на сайте будут ограничены по скорости.
Справочник по классу
-
check(string $key, int $capacity, int $seconds[, int $cost = 1]) -
Параметры: - $key (string) – Имя ведра
- $capacity (int) – Количество токенов в ведре
- $seconds (int) – Количество секунд, необходимое для полного заполнения ведра
- $cost (int) – Количество токенов, затрачиваемых на это действие
Возвращает: true, если действие может быть выполнено, false - если нет
Тип возвращаемого значения: bool
Проверяет, есть ли в ведре токены или слишком много их было использовано в отведенный период времени. При каждой проверке доступные токены уменьшаются на $cost, если проверка успешна.
-
getTokentime() -
Возвращает: Количество секунд до доступности следующего токена. Тип возвращаемого значения: целое число После того, как
check()был выполнен и возвратил false, этот метод может быть использован для определения времени до появления нового токена и возможности повторной попытки действия. В данном случае минимальное время ожидания составляет одну секунду.
-
remove(string $key) : self -
Параметры: - $key (string) – Имя ведра
Возвращает: $this
Тип возвращаемого значения: self
Удаляет и сбрасывает ведро. Не завершается с ошибкой, если ведро не существует.
© 2014–2020 British Columbia Institute of Technology
Licensed under the MIT License.
https://codeigniter.com/user_guide/libraries/throttler.html