Brute Force Protection
Combodo's customers only
- name:
- Brute Force Protection
- description:
- Securing the login process
- version:
- 1.1.1
- release:
- 2023-07-13
- itop-version-min:
- 2.7.9
- code:
- itop-fence
- diffusion:
- ITSM Designer
- php-version-max:
- PHP 8.1
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:
-
slowdown: user has to wait between login trials.
-
recaptcha: recaptcha is activated on the login page
-
captcha: a captcha image is added to the login page
-
login invalid: Could be used to deny iTop access from a given IP range for eg.
-
login invalid for a limited duration: applies to a specific
login
-
no answer: do not reply to login request, should be limited to some conditions
-
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 |
---|---|---|
2023-07-13 | 1.1.1 | * N°6511 - Remove tests folder from builds |
2023-07-05 | 1.1.0 | * N°5411 - Add compatibility with PHP 8.1 (warning changes min PHP version to 7.2.5) |
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
Installation
-
Use the Standard installation process
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 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, ), ), ),
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 |
Checkers & Countermeasure
The main work is to associate checkers with countermeasure inside the configuration's checker_to_countermeasure entry, using optionally these filters:
-
max_level: When you set a max level, the returned level must be below or equal to
max_level
to apply the countermeasure -
min_level: When you set a min level, the returned level must be above or equal to
min_level
to apply the countermeasure -
login_mode_included - if not specified, all login_modes are included
-
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_scoreIf 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.
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).
Writing your own checker
IpRangeChecker
. And then read those explanationsWriting 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 thecheck 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
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
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())
.