Sidebar

Combodo

iTop Extensions

Brute Force Protection

Combodo's customers only

name:
Brute Force Protection
description:
Securing the login process
version:
1.0.7
release:
2022-08-31
itop-version-min:
2.7.2
code:
itop-fence
diffusion:
ITSM Designer
php-version-max:
PHP 8.0

This extension helps you secure the iTop login process against brute force attacks. (see wikipedia and especially the chapter Countermeasures)

Features

Basically this extension watch every login tentative and on some conditions:

  • If the login comes from some IP ranges
  • If the login fails (invalid login or invalid password)
  • If a captcha image was used to login and returns a high score
  • If a recaptcha returns a low score

It can triggers brut force countermeasures, which can be any of those:

  1. slowdown: user has to wait between login trials.
  2. recaptcha: recaptcha is activated on the login page
  3. captcha: a captcha image is added to the login page
  4. login invalid: Could be used to deny iTop access from a given IP range for eg.
  5. login invalid for a limited duration: applies to a specific login
  6. no answer: do ​not reply to login request, should be limited to some conditions
  7. no answer for a limited duration: applied to a particular login

Conditions and countermeasures are explained in further details below.

Revision History

Release Date Version Comments
2022-08-31 1.0.7 * Fix wrong calls to ResetCurrentCmdbChange()
* Fix PHP notices in Strategy manager and Captcha handler
2021-12-17 1.0.6 * Removed gregwar/captcha demo files
2021-06-03 1.0.5 New 'enabled' module config parameter
2020-12-04 1.0.4 * Fix crash when login with a admin user in admin only mode
* Fix REST comment field not working anymore
2020-10-27 1.0.3 Fix some DE translations
2020-08-27 1.0.2 Fix error when iTop is readonly
2020-06-04 1.0.1 Fix bug : PHP Notice “Undefined index: login_temp_auth_user”
Requires at least PHP 7.1.3
2020-02-05 1.0.0 First public version

Limitations

  • The scripts called using CLI may not be secured by this extension.
  • The login_mode form is the only one that can interact with captcha and recaptcha.
  • By default this extension does not perform any securement, until you configure it.

Requirements

  • iTop 2.7 or above
Requires at least PHP 7.1.3

Installation

Configuration

You'll find below a series of configuration examples, they vary in complexity.

Disable this extension

configuration.php
   'itop-fence' => array (
      // if false, iTop Fence will be entirely disabled
      'enabled' => false,
   ),

Slowdown example

You can use this minimal configuration, which slowdown after 3 failed logins:

configuration.php
'itop-fence' => array (
   // Associate countermeasure with checkers, 
   // optionnaly filtering them with levels and login_mode.
   'checker_to_countermeasure' => array (
      //The most basic configuration : if the login fail three times, slowdown the auth process
      array (
        'checker' => 'Combodo\\iTop\\Fence\\Checker\\LoginFailedListener',
        'countermeasure' => 'Combodo\\iTop\\Fence\\Countermeasure\\Slowdown',
        'min_level' => 3,
      ),
   ),
),

Lock example

This configuration, with lock a login for one hour after 3 failed logins:

configuration.php
    'itop-fence' => array (
        'no_answer_duration' => 3600,
        'checker_to_countermeasure' => array (
            0 => array (
                'checker' => 'Combodo\\iTop\\Fence\\Checker\\LoginFailedListener',
                'countermeasure' => 'Combodo\\iTop\\Fence\\Countermeasure\\NoAnswerUntil',
                'min_level' => 3,
            ),
        ),
    ),

Captcha example

If you want to always display a captcha:

configuration.php
    'itop-fence' => array (
        'checker_to_countermeasure' => array (
            0 => array (
                'checker' => 'Combodo\\iTop\\Fence\\Hybrid\\Captcha',
                'countermeasure' => 'Combodo\\iTop\\Fence\\Countermeasure\\LoginInvalid',
                'max_level' => 5,
                'login_mode_included' => ['form']
            ),
        ),
    ),
Captcha are not usable in other login_mode than 'form'

Captcha in IP range example

In this example we want to:

  • Let users with IP in a trusted range, login without captcha,
  • Ask users to fill a captcha if their IP is not trusted and they use the “form” login_mode
  • Do not answer in other situation
configuration.php
    'itop-fence' => array (
        // Define trusted IPs
        'trusted_ip_list' => array (
            0 => '::1', // An IP mask
            1 => '127.0.0.1',  //  A single IP
            2 => '192.168.55.0/24',  // A subnet
        ),
        'malicious_ip_list' => array (
        ),
        'checker_to_countermeasure' => array (
            // If login_mode = 'form' and IP in trusted list
            //   => Ask for a captcha image to be filled
            0 => array (
                'checker' => 'Combodo\\iTop\\Fence\\Checker\\IpRangeChecker',
                'countermeasure' => 'Combodo\\iTop\\Fence\\Hybrid\\Captcha',
                'max_level' => 1,
                'login_mode_included' => ['form']
            ),
            // Else if login_mode other than 'form' and IP in trusted list
            //   => No answer
            1 => array (
                'checker' => 'Combodo\\iTop\\Fence\\Checker\\IpRangeChecker',
                'countermeasure' => 'Combodo\\iTop\\Fence\\Countermeasure\\NoAnswer',
                'max_level' => 1,
                'login_mode_excluded' => ['form']
            ),
            // Else IP NOT in trusted list
            //   => No Answer
            2 => array (
                'checker' => 'Combodo\\iTop\\Fence\\Checker\\IpRangeChecker',
                'countermeasure' => 'Combodo\\iTop\\Fence\\Countermeasure\\NoAnswer',
                'min_level' => 2,
            ),
        ),
    ),
For each checker, the configuration file is parsed to activate applicable countermeasures

Configuration - full example

Here is a complex example of configuration:

configuration.php
'itop-fence' => array (
   // if false, iTop Fence will be entirely disabled
   'enabled' => true,
   //recaptcha will not be activable until both two keys are configured
   // if you have no key, remove following entry from your configuration
   'recaptcha_public_key' => NULL, 
   'recaptcha_private_key' => NULL,
   // IpRangeChecker base configuration. 
   // NB: You can use ipv4 and ipv6, you can also use subnets   
   'trusted_ip_list' => array('::1', '127.0.0.1'),     
   'malicious_ip_list' => array(),   //you can use ipv4 and ipv6, you can also use subnets 
 
   // Associate countermeasure with checkers, 
   // optionally filter them with levels and login_mode.
   'checker_to_countermeasure' => array (
      //The most basic configuration : if the login fail three times, slowdown the auth process
      array (
        'checker' => 'Combodo\\iTop\\Fence\\Checker\\LoginFailedListener',
        'countermeasure' => 'Combodo\\iTop\\Fence\\Countermeasure\\Slowdown',
        'min_level' => 3,
      ),
      // Recaptcha is meant to be used only with the login_mode "form"
      // 0.4 is a really bad score, below let's consider the user as a BOT
      // and lie him by saying that the password is invalid 
      array (
        'checker' => 'Combodo\\iTop\\Fence\\Hybrid\\Recaptcha',
        'countermeasure' => 'Combodo\\iTop\\Fence\\Countermeasure\\LoginInvalid',
        'max_level' => 0.4,
        'login_mode_included' => ['form'],
      ),
      // Better score but still suspicious, let's add an image captcha in order to check
      array (
        'checker' => 'Combodo\\iTop\\Fence\\Hybrid\\Recaptcha',
        'countermeasure' => 'Combodo\\iTop\\Fence\\Hybrid\\Captcha',
        'min_level' => 0.4,
        'max_level' => 0.6,
        'login_mode_included' => ['form'],
      ),
      // IpRangeChecker: 
      // if the ip is not from the trusted list and the login mode is form, let's add a captcha
      array (
        'checker' => 'Combodo\\iTop\\Fence\\Checker\\IpRangeChecker',
        'countermeasure' => 'Combodo\\iTop\\Fence\\Hybrid\\Captcha',
        'max_level' => 1,
        'login_mode_included' => ['form'],
      ),
      // IpRangeChecker: 
      // if the ip is not trusted and the login mode is NOT form, let's refuse to answer
      // this require you to list every and each non interactive client's IP to iTop
      // generally, you'll need to provide a VPN for mobile users as their IP may vary otherwise
      array (
        'checker' => 'Combodo\\iTop\\Fence\\Checker\\IpRangeChecker',
        'countermeasure' => 'Combodo\\iTop\\Fence\\Countermeasure\\NoAnswerUntil',
        'max_level' => 1,
        'login_mode_excluded' => ['form'],
      ),  
      // IpRangeChecker: 
      // if the ip is from the malicious list, we don't even bother to answer.
      // note: you should use the malicious list as an emergency tool, 
      // Firewall rules offer better performance to handle thousand of rules
      array (
        'checker' => 'Combodo\\iTop\\Fence\\Checker\\IpRangeChecker',
        'countermeasure' => 'Combodo\\iTop\\Fence\\Countermeasure\\NoAnswerUntil',
        'min_level' => 2,
      ),
   ),
),

Parameters

Here is the details of each possible parameter for this extension:

Usage Parameters Purpose
activation enabled to inactivate the extension, in case of issue with it
ip range trusted_ip_list An array of IPs, masks and subnets, which are trusted
malicious_ip_list An array of IPs, masks and subnets, which are suspicious
recaptcha recaptcha_public_key Those keys need to be negotiated with Google. They are required for the recaptcha to be activated by iTop
recaptcha_private_key
recaptcha_minimum_score Used in countermeasure only, its a float between 0 and 1, below which we don't trust the requester to be a human, by default it's set to 0.4
slowdown slowdown_initial_duration Duration in micro seconds of the first sleep period
slowdown_duration_incrementation Number of micro seconds added to previous sleep period
slowdown_duration_max When the sleep period reach this number of micro seconds, it stops increasing
login invalid login_always_invalid_duration number of seconds during which a login will be flagged as invalid
no answer no_answer_duration number of seconds during which for a login no reply will be provided
no_answer_http_response_code the http response code to use (429 by default)
all max_try_without_security default 3
Countermeasure starts at MAX(max_try_without_security, min_level) + 1

Checkers & Countermeasure

The main work is to associate checkers with countermeasure inside the configuration's checker_to_countermeasure entry, using optionally these filters:

  1. max_level: When you set a max level, the returned level must be below or equal to max_level to apply the countermeasure
  2. min_level: When you set a min level, the returned level must be above or equal to min_level to apply the countermeasure
  3. login_mode_included - if not specified, all login_modes are included
  4. login_mode_excluded - if not specified, none are excluded

If a login_mode is included and excluded at the same time, I can't predict the behavior, just change your configuration

Checkers

Each security checker returns a level of risk. Depending on the level reached, iTop activates countermeasures.
The level depends on the security checker:

What is returned by the Checker:

  • login failed: the number of successive fails
  • ip range:
    • level 1: the IP is not in the trusted list (trusted_ip_list)
    • level 2: the IP is in the malicious list (malicious_ip_list)
  • recaptcha: a float between 0 and 1, it's the confidence about the user being a human (1 : max trust)
  • captcha image: the number of miss-typed characters
Checker Behaviour
login failed It returns the number of successive fails for a particular login. This number is stored in an object called Login audit. Combine it with min_level or max_level to trigger countermeasure
ip range This security checkers is enabled only if trusted_ip_list and/or malicious_ip_list are configured. It is compatible with both IPv4 and IPv6. You can write single IP and/or IP masks. This array is not intended to be huge. It is preferable to use a dedicated firewall (like iptables) instead. Please consider this feature as a mean to address rapidly an attack.
Captcha image As a security checker: it does always enforce the display of a captcha in the login form (It has no impact on other login_modes). The returned level is the number of miss-typed characters (more precisely it is the Levenshtein distance).
Recaptcha It is enabled only if both recaptcha_public_key and recaptcha_private_key are configured (see https://www.google.com/recaptcha/admin to generate yours).
As a security checker: it does always enforce the use of the google's recaptcha service.
The returned level is a float between 0 and 1, it represent the confidence about the user beeing a human (1 : max trust). For details, see https://developers.google.com/recaptcha/docs/v3#interpreting_the_score
If the user's score is below recaptcha_minimum_score, the countermeasure is applied.

Question: If a trusted_ip_list and a malicious_ip_list are set and the IP is not in the first one but is in the second, the level returned? Answer: The returned level is 2.

Value to use in the configuration file

  • login failed: Combodo\\iTop\\Fence\\Checker\\LoginFailedListener
  • ip range: Combodo\\iTop\\Fence\\Checker\\IpRangeChecker
  • captcha: Combodo\\iTop\\Fence\\Hybrid\\Captcha |
  • recaptcha: Combodo\\iTop\\Fence\\Hybrid\\Recaptcha |

Countermeasures

Countermeasure Behaviour
Slowdown This countermeasure is maybe the most efficient: if enabled, iTop fence will sleep during slowdown_initial_duration micro seconds, before providing a response, then it will increase this sleep duration by slowdown_duration_incrementation until it reaches slowdown_duration_max, then it stops increasing the sleeping duration.
Captcha image If the user type a wrong captcha at this stage, the credentials will be considered as “wrong” and the user invited to enter them again.
Recaptcha It is usable only if both recaptcha_public_key and recaptcha_private_key are configured (see https://www.google.com/recaptcha/admin to generate yours).
If the user's score is below recaptcha_minimum_score, the login will be refused with an error “not authorized”.
LoginInvalid This one is somehow extremist: if enabled, even if the credentials are valid, the response will be “invalid”. Apart from denying access to iTop from outside an IP range, not sure you will need this.
LoginInvalidUntil The same as LoginInvalid but limited in time: once it expires, it let on attempt to login before being re-enabled. Each cycle start with an allowed attempt. When this countermeasure is applied, it stores in the iTopFenceLogin object (labelled “Login audit” in english), the date-time until which an invalid answer will be provided if this login is used.
NoAnswer If enabled, the login attempt will be stopped.
NoAnswerUntil Same as NoAnswer but limited in time: once it expires, the login can be used again. When this countermeasure is applied, it stores in the iTopFenceLogin object (labelled “Login audit” in english), the date-time until which no answer will be provided if this login is used.

Note: there is possibility for the NoAnswer and NoAnswerUntil, to display an error message, also this is rather incoherent with the purpose of NoAnswer. For this just define this dictionary entry: UI:iTopFence:NoAnswerUntil:Message.

Value to use in the configuration file:

  • Slowdown: Combodo\\iTop\\Fence\\Countermeasure\\Slowdown
  • Captcha image: Combodo\\iTop\\Fence\\Hybrid\\Captcha
  • Recaptcha: Combodo\\iTop\\Fence\\Hybrid\\Recaptcha
  • LoginInvalid: Combodo\\iTop\\Fence\\Countermeasure\\LoginInvalid
  • LoginInvalidUntil: Combodo\\iTop\\Fence\\Countermeasure\\LoginInvalidUntil
  • NoAnswer: Combodo\\iTop\\Fence\\Countermeasure\\NoAnswer
  • NoAnswerUntil: Combodo\\iTop\\Fence\\Countermeasure\\NoAnswerUntil

Filtering logs

There is a global parameter in iTop which allow to configure how talkative a log should be for a given module

log_level_min: You can filter/disable the logs by adding an entry into log_level_min.

  • Info: (default) use this value in production
  • Debug: if you are trying to configure itop fence, you should switch to this level
  • Trace: This level enable more logs than Debug, most of the time you don't need this.
$MySettings = array(
    // ...
    'log_level_min' => array (
       // ...
       'iTopFence' => 'Info',
       // ...
    ),
    // ...
);    

Usage

The above example give you a hint at how to properly use iTop fence : you define countermeasure that are called when checker trigger

optionally filtering them to a specific level and/or to specific login_mode.

if checker_to_countermeasure is empty (this is the case by default), then no rules are applied at all!

Question: Which countermeasure is applied, when two or more are triggered by a different checker?
Answer:

  • NoAnswer and NoAnswerUntil, take over all other countermeasures, which are not applied.
  • Then LoginInvalid and LoginInvalidUntil, will take precedence, on the remaining countermeasures
  • Then, the 3 others work in parallel

Customization

iTop Fence is written as an plugin system: so you can write your own checkers and countermeasures.

Writing your own checkers and countermeasures require very few code. This is made possible because they have no dependencies with each other (the StrategyManager is the glue bringing them together based on the checker_to_countermeasure configuration).

You can dig deeper in iTop's plugin system by reading this documentation : https://wiki.combodo.com/doku.php?id=latest:customization:authentication

Writing your own checker

Simple example are better than convoluted explanations, so you should take a look at IpRangeChecker. And then read those explanations

Writing your own checker is extremely easy, you just have to plug yourself in the login process of iTop, the easiest way is to extend AbstractLoginFSMExtension (see https://wiki.combodo.com/doku.php?id=latest:customization:authentication#extending_the_authentication_process for a full list of possibilities).

Once you've done this, you'll just have to call StrategyManager::enable(self::class, $yourOwnLevelSystem); when relevant. please note that this call must take place:

  • before the standard login procedure
    • so the ListSupportedLoginModes() must at least return 'before'
  • during the start and during the check credential states

tip: StrategyManager::IsCheckerUsed(self::class) return true only if the checker if configured for the current login_mode.

Appending content to the login form

simple example are still better than convoluted explanations, so you should take a look at Captcha::GetLoginData(). And then read those explanations.

This is easily feasible by defining a GetLoginData method. Please note that this probably mean that you checker is not compatible with other login mode than form, thus, every time a configuration reference this checker, it should filter using 'login_mode_included' ⇒ ['form']. This also mean that another checker should cover the case of 'login_mode_excluded' ⇒ ['form'],.

Please refer to https://wiki.combodo.com/doku.php?id=latest:customization:authentication#screen_customization in order to discover how to write the GetLoginData method.

Writing your own countermeasure

Once again simple example are better than convoluted explanations, so you should take a look at LoginInvalid. And then read those explanations.

In order to create your own countermeasure, you just have to extend AbstractCountermeasure and write your own OnCheckCredentials method.

  • if you want to let the login process continue, return LoginWebPage::LOGIN_FSM_CONTINUE
  • if you want to stop the login process
    • set to a relevant error code (ie $iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS)
    • return LoginWebPage::LOGIN_FSM_ERROR

tip: $this→IsEnabled() return true only if you have been activated has a countermeasure.

Writing Hybrid classes that are both checker and countermeasure

This is the case of captcha and recaptcha, so, you know the idea : you should take a look at Captcha. And then read those explanations ;)

You have to call StrategyManager::enable(self::class, $iLevel) when you detect a suspicious activity, and alway return a relavant value for the statemachine (ie return LoginWebPage::LOGIN_FSM_ERROR in the OnCheckCredentials method)

Finally, checker and countermeasure are always called by the login FSM, so if you want to perform code only if you are legit, you should do this check if (StrategyManager::IsCheckerUsed(self::class) || $this→IsEnabled()).

extensions/itop-fence.txt · Last modified: 2022/09/12 11:46 (external edit)
Back to top
Contact us