PHPackages                             maba/gentle-force-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. maba/gentle-force-bundle

ActiveSymfony-bundle[Security](/categories/security)

maba/gentle-force-bundle
========================

Symfony bundle that integrates gentle-force library for limiting both brute-force attempts and ordinary requests, using leaky/token bucket algorithm, based on Redis

0.6.3(4y ago)53517.6k—1.9%14[6 issues](https://github.com/mariusbalcytis/gentle-force-bundle/issues)[2 PRs](https://github.com/mariusbalcytis/gentle-force-bundle/pulls)1MITPHPPHP ^7.1 | ^8.0CI failing

Since Jul 2Pushed 4y ago5 watchersCompare

[ Source](https://github.com/mariusbalcytis/gentle-force-bundle)[ Packagist](https://packagist.org/packages/maba/gentle-force-bundle)[ RSS](/packages/maba-gentle-force-bundle/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (5)Dependencies (16)Versions (18)Used By (1)

Gentle-force bundle: brute-force, error and request rate limiting
=================================================================

[](#gentle-force-bundle-brute-force-error-and-request-rate-limiting)

This is a symfony bundle for rate-limiting both brute-force attempts (like invalid credentials) and ordinary requests.

It integrates standalone [gentle-force](https://github.com/mariusbalcytis/gentle-force) library into Symfony framework.

Features
--------

[](#features)

- can be used to limit brute-force attempts;
- can be used for request rate limiting;
- uses leaky / token bucket algorithm. This means that user does not have to wait for next hour or day - additional attempts are possible as time goes by. This also means that requests do not come in big batches when every hour starts;
- handles race-conditions. This is important for brute-force limiting. For example, if 1000 requests are issued at the same time to check same user's password, only configured number of attempts will be possible;
- can have several limits configured for single use-case (for example maximum of 100 requests per minute and 200 per hour);
- does not make assumptions about where and what it's used for - it can be used with user identifiers, API tokens, IP addresses or any other data to group usages;
- provides integration with [Google reCAPTCHA](https://www.google.com/recaptcha/).

Installation
------------

[](#installation)

```
composer require maba/gentle-force-bundle
```

Register bundle inside `AppKernel.php`:

```
new \Maba\Bundle\GentleForceBundle\MabaGentleForceBundle(),
```

### If using recaptcha

[](#if-using-recaptcha)

```
composer require google/recaptcha
```

Import routing in `app/routing.yml`:

```
gentle_force:
    resource: '@MabaGentleForceBundle/Resources/config/routing.xml'
```

Usage
-----

[](#usage)

Usually it's enough to configure listeners in `config.yml` file.

You can also inject limiting service and incorporate your custom logic - see [advanced usage](#advanced-usage) below.

Configuration
-------------

[](#configuration)

### Examples

[](#examples)

Example configuration for API request limiting by IP address and user:

```
maba_gentle_force:
    limits:
        api_request:
                # Allow 10 requests each minute.
                # User can "save up" hour of usage if not using API.
                # This means up to 610 requests at once, after that -
                # 10 requests per minute, which could again save-up up to 610.
            - max_usages: 10
              period: 1m
              bucketed_period: 1h
    listeners:
        - path: ^/api/          # automatically limit matching requests
          limits_key: api_request
          identifiers: [ip]     # limit by IP address

        - path: ^/api
          limits_key: api_request
            # additionally limit by username, if available
          identifiers: [username]
```

Example configuration for limiting failures in login form:

```
maba_gentle_force:
    limits:
        credentials_error:
                # Allow 3 errors per hour,
                # 2 additional errors if no errors were made during last hour:
            - max_usages: 3
              period: 1h
              bucketed_usages: 2

                # Allow 10 errors per day:
            - max_usages: 10
              period: 1d
    listeners:
        - path: ^/login         # match only POST requests to /login*
          methods: [POST]
          limits_key: credentials_error
          identifiers: [ip]
          strategy: recaptcha_page
            # only status 302 is successful in our case
            # response code 200 usually displays error message,
            # while we redirect after success
          success_statuses: ['302']
    strategies:
        recaptcha_template:
            template: custom.html.twig  # optional - overwrite template
    recaptcha:
        site_key: my_recaptcha_site_key # get this at google.com/recaptcha
        secret: my_recaptcha_secret     # this also
```

### Limits

[](#limits)

Limits are defined by concrete use-case. It may be your API request, credentials failure, password reset attempt, registering for email subscription, checking if username is available etc.

Use any unique key for identifying limit configuration - use same limit key later to calculate if concrete limit is reached.

Each limit configuration can have several limits defined. This is useful if you want to have blocking with bigger intervals on more repeating failures or requests. For example, you can have different limits for minute, day and week for the same use-case. If any of defined limits is reached, request is blocked.

You can configure following keys for limits:

- `max_usages`;
- `period`. Measured in seconds, you can use suffixes `s` (seconds), `m` (minutes), `h` (hours), `d` (days) or `w` (weeks);
- `bucketed_usages`. Optional, additional usages available on top of `max_usages`. Does not effect speed of additional tokens (see [token bucket](https://en.wikipedia.org/wiki/Token_bucket));
- `bucketed_period`. Optional, mutually exclusive with `bucketed_usages`. Period for additional usages to be added on top of `max_usages` if not being used. Period suffixes available.

### Listeners

[](#listeners)

Each configured listener can potentially block the request.

#### Filtering

[](#filtering)

To filter requests on which limit must be applied, use following keys:

- `path`. Regex to match request path;
- `methods`. List of request methods;
- `hosts`. List of hosts.

#### Limiting

[](#limiting)

You must always configure `limits_key` and `identifiers` for each listener to use for limiting requests.

`identifiers` are used to specify items from request that will be used for limiting. `ip` and `username` identifiers are available by default, you can also register [additional identifiers](#additional-identifiers).

If several identifiers are specified, all of them must match for available limit to be decreased.

Keep in mind, that if at least one identifier is unavailable, limit is not applied at all. So, if limiting by `[ip, username]`, unauthorised requests will not be limited at all.

#### Handling successful requests

[](#handling-successful-requests)

For brute-force attempts, bundle needs to check if request was successful or not. By design, bundle checks and increases usage count in advance, even before checking if everything is fine. Thus, if request was valid, this count must be decreased.

For configuring what's considered successful response, use one of the following:

- `success_statuses`. Provide list of HTTP response statuses that indicates successful response;
- `failure_statuses`. Same as `success_statuses`, but in reverse - everything else is considered successful;
- `success_matcher`. Service ID to use for identifying whether response is successful. Service must implement `SuccessMatcherInterface`.

If you skip all three, all requests are considered as a failure - that is, functionality handles basic request limiting.

#### Defining strategy for reached limit

[](#defining-strategy-for-reached-limit)

Use `strategy` key to identify strategy to use if limit for this listener is reached. See [strategies](#strategies) below for more information.

### Strategies

[](#strategies)

Following strategies are available:

- `headers`. Returns pre-configured response with `429 Too Many Requests`status code. This is default one;
- `log`. Does not modify response, just logs failures. Usable in configuration testing phase;
- `recaptcha_headers`. Same as `headers` but adds recaptcha site key. Can be used by JavaScript code to initiate recaptcha widget;
- `recaptcha_template`. Returns HTML response with recaptcha widget. After successfully submitting recaptcha, current page is refreshed.

You can configure and use your own strategy - just provide service ID instead of pre-configured key. Strategy must implement `StrategyInterface`and optionally `ResponseModifyingStrategyInterface` to modify successful responses.

#### Headers

[](#headers)

Configuration options:

- `content`. Content to return in response;
- `content_type`. Content type for response;
- `wait_for_header`. Header name to use in rate exceeded responses. This response header defines minimum time to wait in seconds before repeating the request;
- `requests_available_header`. Header name to use in successful responses to identify how many requests are available at this moment.

#### Log

[](#log)

You can configure `level` to use for logging (defaults to `error`).

#### Recaptcha

[](#recaptcha)

For `recaptcha_headers` you can configure `site_key_header` and `unlock_url_header` to specify header names to use in rate exceeded response to provide configured recaptcha site key and unlock absolute url.

For `recaptcha_template` you can configure `template` to use for generating response. See templates inside the bundle for more information about what data is passed. `TwigBundle` is needed for this strategy to work.

For both strategies, you must install recaptcha (see [installation](#if-using-recaptcha)) and configure recaptcha site data (see configuration examples).

When routing is imported, `maba_gentle_force_unlock_recaptcha` route is available (`POST` method). Pass recaptcha response in `g-recaptcha-response` field using `application/x-www-form-urlencoded`encoding. Empty `200` response means that rate limit was reset. In case of error, `400` response is returned with JSON content, `errors`key will hold array of errors from recaptcha service. See `RecaptchaUnlockController` and JavaScript code in twig templates for more information.

### Redis

[](#redis)

To configure redis client, either use `host` (defaults to `localhost`) or `parameters` and `options` (allows to configure connection to redis sentinels) or `service_id` to provide custom `Predis\Redis` service

You can configure `prefix` for additional prefix for all created keys.

If you prefer to avoid rate limiting at all if redis connection would fail, but still serve requests as usual, configure `failure_strategy`as `ignore`. In case of connection failure, you'd get error logged instead of unhandled exception causing `500` responses.

### Full configuration reference

[](#full-configuration-reference)

```
maba_gentle_force:
    redis:
        host:                 ~
        parameters:           []
        options:
            replication:      ~
            service:          ~
            parameters:
                password:     ~
        service_id:           ~
        prefix:               ~
        failure_strategy:     fail
    limits:
        my_limit_name:
            -
                max_usages: ~
                period: ~
                bucketed_usages: ~
                bucketed_period: ~
    strategies:
        default:              headers
        headers:
            wait_for_header:      null
            requests_available_header: null
            content:              'Too many requests'
            content_type:         'text/plain; charset=UTF-8'
        log:
            level:                error
        recaptcha_headers:
            site_key_header:      null
            unlock_url_header:    null
        recaptcha_template:
            template:             null
    listeners:
        -
            path:                 ^/
            limits_key:           ~
            identifiers:          []
            strategy:             ~
            success_matcher:      ~
            success_statuses:     []
            failure_statuses:     []
            methods:              []
            hosts:                []
    recaptcha:
        site_key:             ~
        secret:               ~
    listener_priorities:
        default: 1000
        post_authentication: 0
```

Additional identifiers
----------------------

[](#additional-identifiers)

You can provide additional identifiers to configure in your listeners.

You need to create service which implements `IdentifierProviderInterface`and tag it with `maba_gentle_force.identifier_provider`(provide name in `identifierType` attribute).

For example:

```
