FastSitePHP\Security\Web\RateLimit

Rate limiting can be used to limit the number of requests or actions that a user makes in a given time frame.

Some examples:
  - A Web API allowing users to submit no more than 1 request every second.
  - No more than 2 new accounts per day per IP address.
  - Limit users from sending more than 10 messages per hour.

FastSitePHP's Rate Limit class is designed to provide an easy-to-use interface for defining and enforcing rate limits.

Código Fonte

GitHub

Código de Exemplo

Segurança - Limitação de Frequência

// Classe de Limitação de Frequência
$rate_limit = new \FastSitePHP\Security\Web\RateLimit();

// Utilizando a classe RateLimit requer uma instância de [\FastSitePHP\Data
// \KeyValue\StorageInterface].
// Neste exemplo SQLite é utilizado. Quando múltiplos servidores são
// usados atrás de um balanceador de carga, um bd de cache em memória como
// o Redis pode ser utilizado.
$file_path = sys_get_temp_dir() . '/ratelimit-cache.sqlite';
$storage = new \FastSitePHP\Data\KeyValue\SqliteStorage($file_path);

// Há duas opções obrigatórias [storage] e [id]. [id] representa o usuário -
// Endereço de IP, ID de Usuário etc.
//
// [max_allowed] e [duration] serão comumente utilizadas e representam a
// taxa na qual o evento é permitido. Se não especificado, então, um
// padrão de 1 é usado o qual permite 1 requisição por segundo.
$options = [
    'max_allowed' => 1, // Requisições, Eventos etc
    'duration' => 1, // Em segundos
    'storage' => $storage,
    'id' => $_SERVER['REMOTE_ADDR'],
];

// Verifique a Requisição
list($allowed, $headers) = $rate_limit->allow($options);
// $allowed = bool
// $headers = Array de cabeçalhos pode ser utilizado para lógica ou
//            ou enviado com a resposta

// Uma coisa para estar ciente ao filtrar por IP é que vários usuários podem
// estar como o mesmo IP se eles estiverem acessando seu site de um mesmo
// escritório ou localização.

// Exemplos de opções:

// Limitar a 10 requisições a cada 20 segundos
$options = [ 'max_allowed' => 10, 'duration' => 20, ];

// Limitar a 2 requisições por minuto
$options = [ 'max_allowed' => 2, 'duration' => 60, ];

// Limitar a 2 requisições por dia
$options = [ 'max_allowed' => 10, 'duration' => (60 * 60 * 24), ];

// Se estiver utilizando a classe [RateLimit] para múltiplas utilizações,
// então, você precisa especificar uma chave opcional.
$options = [ 'key' => 'messages-sent' ];
$options = [ 'key' => 'accounts-created' ];

// A classe [RateLimit] permite diferentes algorítimos de limitação de
// taxa; o padrão é 'fixed-window-counter' o qual coloca uma quantidade
// fixa no número de requisições para a duração dada, mas permite rajadas.
// O 'token-bucket' permite limitar a taxa por uma taxa
// cronometrada, entretanto, isso pode permitir um número maior de requisições
// do que o especificado [max_allowed].
//
// Para utilização básica com um número pequeno de [max_allowed] tal como
// "1 requisição por segundo",  ele comportarão-se da mesma forma, no
// entanto, se especificar um número maior como "10 requisições por 20
// segundos", então, haverá um diferença, assim se você estiver utilizando
// limitação de taxa para requisições web com um número grande você
// pode querer comparar as diferenças utilizando código exemplo e ver links
// relacionados nos documentos da API.
//
$options = [ 'algo' => 'fixed-window-counter' ];
$options = [ 'algo' => 'token-bucket' ];

// A função [filterRequest()] pode ser utilizada para filtrar a requisição.
// Ao ser utilizada, se a limitação de taxa do usuário é atingida,
// então, uma resposta 409 [Too Many Requests] é enviada e [exit()] é
// chamada para parar a execução do script.
$filter_request = function() use ($app, $storage) {
    // Obtém o IP de Usuário (exemplo se estiver utilizando um balanceador
    // de carga)
    $req = new \FastSitePHP\Web\Request();
    $user_ip = $req->clientIp('from proxy');

    // Check rate
    $rate_limit = new \FastSitePHP\Security\Web\RateLimit();
    $rate_limit->filterRequest($app, [
        'storage' => $storage,
        'id' => $user_ip,
    ]);
};
$app->get('/api', function() {})->filter($filter_request);

// Quando utilizar [filterRequest()] os seguintes Cabeçalhos de Response
// podem ser enviados para o cliente dependendo de quais opções são
// utilizadas
//   Retry-After            Cabeçalho Padrão
//   X-RateLimit-Limit      Descrição legível por humanos do limite da taxa
//   X-RateLimit-Remaining  Requisições permitidas para o período de tempo dado
//   X-RateLimit-Reset      Registro de data e hora Unix para o limite redefinir

Métodos

filterRequest(Application $app, array $options)

Filter the request if it is allowed based on a rate limit. If the user's rate limit is reached then a 429 [Too Many Requests] response is sent and [exit()] is called to stop the script execution.

The same options used for [allow()] are used here.

allow(array $options)

Check if a request or action is allowed based on a rate limit.

Required Options:
    - [storage]: Object - Instance of [FastSitePHP\Data\KeyValue\StorageInterface]
    - [id]: Id assigned to the user or request. For example the client's IP Address or a user id

Common Optional Options:
    - [max_allowed] (int): Maximum number of requests allowed for the specified duration
    - [duration] (int): Time in sections

Additional Options:
    - [key]: String value to prefix when saving a key-value-pair.
      This would be used if you are using the RateLimiter for multiuple actions in the same site.
    - [algo]: Algorithm to use ['fixed-window-counter' or 'token-bucket']. Defaults to 'fixed-window-counter'.

Retorna: array - list($allowed, $headers)