Combodo's customers only
This extension helps you secure the iTop login process against brute force attacks. (see wikipedia and especially the chapter Countermeasures)
Basically this extension watch every login tentative and on some conditions:
It can triggers brut force countermeasures, which can be any of those:
login
login
Conditions and countermeasures are explained in further details below.
Release Date | Version | Comments |
---|---|---|
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 |
login_mode
form is the only one that can interact with captcha and recaptcha.You'll find below a series of configuration examples, they vary in complexity.
'itop-fence' => array ( // if false, iTop Fence will be entirely disabled 'enabled' => false, ),
You can use this minimal configuration, which slowdown after 3 failed logins:
'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, ), ), ),
This configuration, with lock a login for one hour after 3 failed logins:
'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, ), ), ),
If you want to always display a captcha:
'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'] ), ), ),
In this example we want to:
login_mode
'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, ), ), ),
Here is a complex example of configuration:
'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, ), ), ),
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 |
The main work is to associate checkers with countermeasure inside the configuration's checker_to_countermeasure entry, using optionally these filters:
max_level
to apply the countermeasuremin_level
to apply the countermeasureIf a login_mode is included and excluded at the same time, I can't predict the behavior, just change your configuration
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:
trusted_ip_list
) malicious_ip_list
) 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
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:
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
.
$MySettings = array( // ... 'log_level_min' => array ( // ... 'iTopFence' => 'Info', // ... ), // ... );
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:
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).
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:
ListSupportedLoginModes()
must at least return 'before'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.
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.
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.
LoginWebPage::LOGIN_FSM_CONTINUE
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS
)LoginWebPage::LOGIN_FSM_ERROR
tip: $this→IsEnabled()
return true only if you have been activated has a 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())
.