mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-11-04 23:48:22 +00:00
[Web] Add TFA Ratelimit
This commit is contained in:
4 files changed
+42
No files matched your search
@@ -1857,6 +1857,40 @@ function get_tfa($username = null, $id = null) {
|
||||
}
|
||||
}
|
||||
function verify_tfa_login($username, $_data) {
|
||||
global $redis;
|
||||
global $TFA_MAX_FAILS;
|
||||
global $TFA_FAIL_WINDOW;
|
||||
|
||||
if (empty($username)) {
|
||||
return false;
|
||||
}
|
||||
// Count failed second factors per account, so codes cannot be guessed from many addresses
|
||||
$fails_key = 'TFA_FAILS_' . $username;
|
||||
if (intval($redis->get($fails_key)) >= $TFA_MAX_FAILS) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $username, '*'),
|
||||
'msg' => 'tfa_login_locked'
|
||||
);
|
||||
$verified = false;
|
||||
}
|
||||
else {
|
||||
$verified = verify_tfa_token($username, $_data);
|
||||
}
|
||||
if ($verified !== true) {
|
||||
// The window starts with the first failure and is not extended by further attempts
|
||||
if ($redis->incr($fails_key) == 1) {
|
||||
$redis->expire($fails_key, $TFA_FAIL_WINDOW);
|
||||
}
|
||||
// Same message format as failed passwords, so the default fail2ban rule counts it
|
||||
error_log("mailcow UI: Invalid password for " . $username . " (second factor) by " . $_SERVER['REMOTE_ADDR']);
|
||||
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $username . " (second factor) by " . $_SERVER['REMOTE_ADDR']);
|
||||
return false;
|
||||
}
|
||||
$redis->del($fails_key);
|
||||
return true;
|
||||
}
|
||||
function verify_tfa_token($username, $_data) {
|
||||
global $pdo;
|
||||
global $yubi;
|
||||
global $u2f;
|
||||
|
||||
@@ -169,6 +169,12 @@ $SESSION_NAME = "MCSESSID";
|
||||
// Label for OTP devices
|
||||
$OTP_LABEL = "mailcow UI";
|
||||
|
||||
// Failed second factor logins (TOTP, Yubico OTP, WebAuthn) of an account before its second factor is locked
|
||||
$TFA_MAX_FAILS = 10;
|
||||
|
||||
// Time (in s) from the first failed second factor login until the counter and the lock are reset
|
||||
$TFA_FAIL_WINDOW = 900;
|
||||
|
||||
// How long to wait (in s) for cURL Docker requests
|
||||
$DOCKER_TIMEOUT = 60;
|
||||
|
||||
|
||||
@@ -641,6 +641,7 @@
|
||||
"temp_error": "Temporärer Fehler",
|
||||
"text_empty": "Text darf nicht leer sein",
|
||||
"tfa_token_invalid": "TFA-Token ungültig",
|
||||
"tfa_login_locked": "Zu viele fehlgeschlagene Zwei-Faktor-Anmeldungen, bitte später erneut versuchen",
|
||||
"tfa_removal_blocked": "Zwei-Faktor-Authentifizierung kann nicht entfernt werden, da sie für Ihr Konto erforderlich ist.",
|
||||
"tls_policy_map_dest_invalid": "Ziel ist ungültig",
|
||||
"tls_policy_map_entry_exists": "Eine TLS-Richtlinie \"%s\" existiert bereits",
|
||||
|
||||
@@ -517,6 +517,7 @@
|
||||
"group_send_as_invalid": "Send-as address %s is invalid or unknown",
|
||||
"iam_sync_mode_invalid": "Invalid sync mode",
|
||||
"iam_sync_unavailable": "The identity provider cannot be synced (Keycloak and LDAP only)",
|
||||
"tfa_login_locked": "Too many failed two-factor logins, please try again later",
|
||||
"tfa_removal_blocked": "Two-factor authentication cannot be removed because it is required for your account.",
|
||||
"alias_domain_invalid": "Alias domain %s is invalid",
|
||||
"alias_empty": "Alias address must not be empty",
|
||||
|
||||
Reference in new issue
Block a user