Increase lock time after each failed login attempt (#2088)

This commit is contained in:
Christophe Maudoux 2020-02-24 21:27:50 +01:00
parent 4ae628bfcd
commit e89c017ff6
23 changed files with 92 additions and 41 deletions

View File

@ -22,6 +22,7 @@ sub defaultValues {
'bruteForceProtectionLockTimes' => '5 15 60 300 600',
'bruteForceProtectionMaxAge' => 300,
'bruteForceProtectionMaxFailed' => 3,
'bruteForceProtectionMaxLockTime' => 900,
'bruteForceProtectionTempo' => 30,
'captcha_mail_enabled' => 1,
'captcha_register_enabled' => 1,

View File

@ -637,6 +637,10 @@ sub attributes {
'default' => 3,
'type' => 'int'
},
'bruteForceProtectionMaxLockTime' => {
'default' => 900,
'type' => 'int'
},
'bruteForceProtectionTempo' => {
'default' => 30,
'type' => 'int'

View File

@ -272,8 +272,6 @@ sub display {
and $req->{error} != PE_FIRSTACCESS
and $req->{error} != PE_BADCREDENTIALS
and $req->{error} != PE_PP_PASSWORD_EXPIRED )
# and ( $req->{error} == PE_TOKENEXPIRED or $req->{error} == PE_NOTOKEN )
)
{
$skinfile = 'error';
@ -282,6 +280,7 @@ sub display {
LANGS => $self->conf->{showLanguages},
AUTH_ERROR => $req->error,
AUTH_ERROR_TYPE => $req->error_type,
LOCKTIME => $req->lockTime(),
(
$req->data->{customScript}
? ( CUSTOM_SCRIPT => $req->data->{customScript} )
@ -382,6 +381,7 @@ sub display {
# Disable all forms on:
# * Logout message
# * Account lock
# * Bad URL error
elsif ($req->{error} == PE_LOGOUT_OK
or $req->{error} == PE_WAIT

View File

@ -69,6 +69,9 @@ has frame => ( is => 'rw' );
# Refresh flag to avoid double cookies sessions to be renewed
has refresh => ( is => 'rw' );
# Scalar to display lock time
has lockTime => ( is => 'rw' );
# Security
#
# Captcha

View File

@ -17,7 +17,11 @@ use constant beforeAuth => 'check';
# INITIALIZATION
has rules => ( is => 'rw', default => sub { [] } );
has rules => (
is => 'rw',
isa => 'ArrayRef',
default => sub { [] }
);
sub init {
my ($self) = @_;

View File

@ -12,6 +12,17 @@ extends 'Lemonldap::NG::Portal::Main::Plugin';
use constant afterData => 'run';
has lockTimes => (
is => 'rw',
isa => 'ArrayRef',
default => sub { [] }
);
has maxAge => (
is => 'rw',
isa => 'Int'
);
sub init {
my ($self) = @_;
if ( $self->conf->{disablePersistentStorage} ) {
@ -35,45 +46,55 @@ sub init {
. ')' );
return 0;
}
if ( $self->conf->{bruteForceProtectionIncrementalTempo} ) {
my $lockTimes = @{ $self->lockTimes } =
sort { $a <=> $b }
map { $_ < $self->conf->{bruteForceProtectionMaxLockTime} ? $_ : () }
grep { /\d+/ }
split /\s+/, $self->conf->{bruteForceProtectionLockTimes};
@{ $self->lockTimes } = ( 5, 15, 60, 300, 600 )
unless $lockTimes;
$self->logger->warn( 'Number of incremental lock time values ('
. "$lockTimes) is higher than failed logins history ("
. $self->conf->{failedLoginNumber}
. ')' )
if ( $lockTimes > $self->conf->{failedLoginNumber} );
my $sum = 0;
$sum += $_ foreach @{ $self->lockTimes };
$self->maxAge($sum);
}
else {
$self->maxAge( $self->conf->{bruteForceProtectionMaxAge} );
}
return 1;
}
# RUNNING METHOD
sub run {
my ( $self, $req ) = @_;
my $now = time;
my @failedLogins = grep {
( $now - $_->{_utime} ) < $self->conf->{bruteForceProtectionMaxAge}
? $_
: ()
} @{ $req->sessionInfo->{_loginHistory}->{failedLogin} };
my $countFailed = @failedLogins;
$self->logger->debug(
" Failed login maxAge = $self->{conf}->{bruteForceProtectionMaxAge}");
my $now = time;
my $countFailed = my @failedLogins =
map { ( $now - $_->{_utime} ) < $self->maxAge ? $_ : () }
@{ $req->sessionInfo->{_loginHistory}->{failedLogin} };
$self->logger->debug( ' Failed login maxAge = ' . $self->maxAge );
$self->logger->debug(
" Number of failed login(s) to take into account = $countFailed");
if ( $self->conf->{bruteForceProtectionIncrementalTempo} ) {
my @incrementalTempo = split /\s+/,
$self->conf->{bruteForceProtectionLockTimes}
|| ( 5, 15, 60, 300, 600 );
$self->logger->warn( 'Number of incremental lock time values ('
. scalar @incrementalTempo
. ') is higher than failed logins history ('
. $self->conf->{failedLoginNumber}
. ')' )
if ( scalar @incrementalTempo > $self->conf->{failedLoginNumber} );
my $lastFailedLoginEpoch = $failedLogins[0]->{_utime} || undef;
return PE_OK unless $lastFailedLoginEpoch;
my $delta = $now - $lastFailedLoginEpoch;
$self->logger->debug(" -> Delta = $delta");
my $waitingTime = $incrementalTempo[ $countFailed - 1 ]
my $waitingTime = $self->lockTimes->[ $countFailed - 1 ]
|| $self->conf->{bruteForceProtectionMaxLockTime};
$self->logger->debug(" -> Waiting time = $waitingTime");
unless ( $delta > $waitingTime ) {
$self->logger->debug("BruteForceProtection enabled");
$req->lockTime($waitingTime);
return PE_WAIT;
}
return PE_OK;
@ -83,7 +104,7 @@ sub run {
if ( $countFailed <= $self->conf->{bruteForceProtectionMaxFailed} );
my @lastFailedLoginEpoch = ();
my $MaxAge = $self->conf->{bruteForceProtectionMaxAge} + 1;
my $MaxAge = $self->maxAge + 1;
# Auth_N-2 failed login epoch
foreach ( 0 .. $self->conf->{bruteForceProtectionMaxFailed} - 1 ) {
@ -100,7 +121,7 @@ sub run {
$self->logger->debug(" -> MaxAge = $MaxAge");
return PE_OK
if ( $MaxAge > $self->conf->{bruteForceProtectionMaxAge} );
if ( $MaxAge > $self->maxAge );
# Delta between the two last failed logins -> Auth_N - Auth_N-1
my $delta =
@ -113,6 +134,7 @@ sub run {
# Account locked
$self->logger->debug("BruteForceProtection enabled");
$req->lockTime( $self->conf->{bruteForceProtectionTempo} );
return PE_WAIT;
}

View File

@ -75,7 +75,7 @@
"PE83":"فشل التحقق من U2F. أعد محاولة الاتصال بالمشرف أو اتصل به",
"PE84":"أنت غير مخول بالدخول إلى هذا الخادم",
"PE85":" الموقع البعيد يطلب جلسة جديدة (ولم يتم تحميل برنامج ترقية الجلسة).\nسجل الخروج و أعد المحاولة",
"PE86":"Your account is locked. You must wait 30s before authenticate again",
"PE86":"Your account is locked. You have to wait",
"PE87":"You must authenticate again to access to Portal",
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
"PE89":"Access not granted on SAML service",
@ -252,6 +252,7 @@
"rightsReloadNeedsLogout":" إعادة تحميل الحقوق تحتاج إلى تسجيل الخروج وتسجيل الدخول مرة أخرى",
"scope":"نطاق",
"search":"Search",
"seconds":"seconds",
"selectIdP":"اختر موفر الهوية الخاص بك",
"service":"Service",
"sendPwd":"Send me a link",

View File

@ -75,7 +75,7 @@
"PE83":"U2F-Überprüfung fehlgeschlagen. Versuchen Sie es erneut oder wenden Sie sich an Ihren Administrator",
"PE84":"Sie sind nicht berechtigt, auf diesen Host zuzugreifen",
"PE85":"Die Gegenseite fragt nach einer neueren Sitzung (und das UpgradeSession-Plugin wurde nicht geladen). Abmelden und erneut versuchen",
"PE86":"Your account is locked. You must wait 30s before authenticate again",
"PE86":"Your account is locked. You have to wait",
"PE87":"You must authenticate again to access to Portal",
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
"PE89":"Zugang zum SAML-Service nicht genehmigt",
@ -252,6 +252,7 @@
"rightsReloadNeedsLogout":"Zum Neuladen der Rechte musst du dich ab- und wieder anmelden",
"scope":"Scope",
"search":"Search",
"seconds":"seconds",
"selectIdP":"Wähle deinen Identitätsanbieter aus",
"service":"Dienst",
"sendPwd":"Send me a link",

View File

@ -75,7 +75,7 @@
"PE83":"U2F verification failed. Retry or contact your administrator",
"PE84":"You're not authorized to access to this host",
"PE85":"The remote site ask for a newer session (and UpgradeSession plugin isn't loaded). Logout and retry",
"PE86":"Your account is locked. You must wait 30s before authenticate again",
"PE86":"Your account is locked. You have to wait",
"PE87":"You must authenticate again to access to Portal",
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
"PE89":"Access not granted on SAML service",
@ -252,6 +252,7 @@
"rightsReloadNeedsLogout": "Rights reloads need to logout and login again",
"scope":"Scope",
"search":"Search",
"seconds":"seconds",
"selectIdP":"Select your Identity Provider",
"service":"Service",
"sendPwd":"Send me a link",

View File

@ -75,7 +75,7 @@
"PE83":"La verificación U2F ha fallado. Reintente o póngase en contacto con su administrador",
"PE84":"Usted no está autorizado a acceder a este servidor",
"PE85":"El sitio remoto pide una nueva sesión (y el plugin UpgradeSession no está cargado). Desconéctese y reintente",
"PE86":"Su cuenta está bloqueada. Espere 30s antes de autenticarse de nuevo",
"PE86":"Your account is locked. You have to wait",
"PE87":"Debe autenticarse de nuevo para acceder al Portal",
"PE88":"Su cuenta debe contar con una dirección de e-mail para poder utilizar la autenticación de dos factores",
"PE89":"Acceso no autorizado al servicio SAML",
@ -252,6 +252,7 @@
"rightsReloadNeedsLogout":"La recarga de derechos necesita desconectarse y conectarse de nuevo",
"scope":"Alcance",
"search":"Buscar",
"seconds":"seconds",
"selectIdP":"Seleccione su proveedor de identidad",
"service":"Servicio",
"sendPwd":"Enviarme un enlace",

View File

@ -75,7 +75,7 @@
"PE83":"U2F verification failed. Retry or contact your administrator",
"PE84":"You're not authorized to access to this host",
"PE85":"The remote site ask for a newer session (and UpgradeSession plugin isn't loaded). Logout and retry",
"PE86":"Your account is locked. You must wait 30s before authenticate again",
"PE86":"Your account is locked. You have to wait",
"PE87":"You must authenticate again to access to Portal",
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
"PE89":"Access not granted on SAML service",
@ -252,6 +252,7 @@
"rightsReloadNeedsLogout":"Rights reloads need to logout and login again",
"scope":"Scope",
"search":"Search",
"seconds":"seconds",
"selectIdP":"Select your Identity Provider",
"service":"Service",
"sendPwd":"Send me a link",

View File

@ -75,7 +75,7 @@
"PE83":"La vérification U2F a échoué. Réessayez ou contactez votre administrateur",
"PE84":"Vous n'êtes pas autorisé à accéder à ce site",
"PE85":"Le site souhaite une authentification plus récente (et le plugin UpgradeSession n'est pas chargé). Déconnectez-vous et réessayez",
"PE86":"Votre compte est verrouillé. Vous devez attendre 30s avant de vous ré-authentifier.",
"PE86":"Votre compte est verrouillé. Avant de pouvoir vous ré-authentifier, vous devez patienter",
"PE87":"Vous devez vous ré-authentifier pour pouvoir accéder au Portail",
"PE88":"Une adresse email doit être renseignée pour pouvoir utiliser l'authentification à double facteurs.",
"PE89":"Accès non autorisé au service SAML",
@ -252,6 +252,7 @@
"rightsReloadNeedsLogout": "Le rechargement des droits nécessite une déconnexion",
"scope": "Informations",
"search":"Chercher",
"seconds":"secondes",
"selectIdP":"Choisissez votre fournisseur d'identité",
"service":"Service",
"sendPwd":"Envoyez-moi un lien",

View File

@ -75,7 +75,7 @@
"PE83":"Verifica U2F fallita. Riprovare o contattare l'amministratore",
"PE84":"Non sei autorizzato ad accedere a questo host",
"PE85":"Il sito remoto richiede una sessione più recente (e il plug-in di UpgradeSession non viene caricato). Disconnetti e riprova",
"PE86":"Il tuo account è bloccato. Devi attendere 30 secondi prima di autenticarti di nuovo",
"PE86":"Your account is locked. You have to wait",
"PE87":"È necessario eseguire nuovamente l'autenticazione per accedere al Portale",
"PE88":"Il tuo account deve avere un indirizzo e-mail per poter utilizzare l'autenticazione a doppio fattore",
"PE89":"Accesso non concesso sul servizio SAML",
@ -252,6 +252,7 @@
"rightsReloadNeedsLogout":"Le ricariche dei diritti necessitano di disconnettersi e di riconnettersi",
"scope":"Ambito",
"search":"Ricerca",
"seconds":"seconds",
"selectIdP":"Seleziona il tuo provider di identità",
"service":"Servizio",
"sendPwd":"Inviami il link",

View File

@ -75,7 +75,7 @@
"PE83":"U2F verification failed. Retry or contact your administrator",
"PE84":"You're not authorized to access to this host",
"PE85":"The remote site ask for a newer session (and UpgradeSession plugin isn't loaded). Logout and retry",
"PE86":"Your account is locked. You must wait 30s before authenticate again",
"PE86":"Your account is locked. You have to wait",
"PE87":"You must authenticate again to access to Portal",
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
"PE89":"Onbevoegde toegang tot de SAML-service",
@ -252,6 +252,7 @@
"rightsReloadNeedsLogout":"Rights reloads need to logout and login again",
"scope":"Scope",
"search":"Search",
"seconds":"seconds",
"selectIdP":"Select your Identity Provider",
"service":"Service",
"sendPwd":"Send me a link",

View File

@ -75,7 +75,7 @@
"PE83":"U2F verification failed. Retry or contact your administrator",
"PE84":"You're not authorized to access to this host",
"PE85":"The remote site ask for a newer session (and UpgradeSession plugin isn't loaded). Logout and retry",
"PE86":"Your account is locked. You must wait 30s before authenticate again",
"PE86":"Your account is locked. You have to wait",
"PE87":"You must authenticate again to access to Portal",
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
"PE89":"Acesso não autorizado ao serviço SAML",
@ -252,6 +252,7 @@
"rightsReloadNeedsLogout":"Rights reloads need to logout and login again",
"scope":"Scope",
"search":"Search",
"seconds":"seconds",
"selectIdP":"Select your Identity Provider",
"service":"Service",
"sendPwd":"Send me a link",

View File

@ -75,7 +75,7 @@
"PE83":"U2F verification failed. Retry or contact your administrator",
"PE84":"You're not authorized to access to this host",
"PE85":"The remote site ask for a newer session (and UpgradeSession plugin isn't loaded). Logout and retry",
"PE86":"Your account is locked. You must wait 30s before authenticate again",
"PE86":"Your account is locked. You have to wait",
"PE87":"You must authenticate again to access to Portal",
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
"PE89":"Access not granted on SAML service",
@ -252,6 +252,7 @@
"rightsReloadNeedsLogout":"Rights reloads need to logout and login again",
"scope":"Scope",
"search":"Search",
"seconds":"seconds",
"selectIdP":"Select your Identity Provider",
"service":"Service",
"sendPwd":"Send me a link",

View File

@ -75,7 +75,7 @@
"PE83":"U2F doğrulaması başarısız oldu. Tekrar deneyin veya yöneticinize başvurun",
"PE84":"Bu ana makineye erişmek için yetkili değilsiniz",
"PE85":"Uzak site daha yeni bir oturum istedi (ve UpgradeSession eklentisi yüklenmedi). Çıkış yap ve tekrar dene",
"PE86":"Hesabınız kilitlendi. Tekrar denemeden önce 30 saniye beklemelisiniz",
"PE86":"Your account is locked. You have to wait",
"PE87":"Portala erişmek için kimliğinizi yeniden doğrulamalısınız",
"PE88":"İki adımlı kimlik doğrulamayı kullanabilmeniz için hesabınıza ait bir e-posta adresi olmalıdır",
"PE89":"SAML servisine erişime izin verilmedi",
@ -252,6 +252,7 @@
"rightsReloadNeedsLogout":"Yetkiler yeniden yüklendiğinde çıkış yapıp tekrar giriş yapmanız gerekir",
"scope":"Kapsam",
"search":"Ara",
"seconds":"seconds",
"selectIdP":"Kimlik Sağlayıcısını seç",
"service":"Servis",
"sendPwd":"Bana bir bağlantı gönder",

View File

@ -75,7 +75,7 @@
"PE83":"Xác minh U2F không thành công",
"PE84":"Bạn không được phép truy cập vào máy chủ lưu trữ này",
"PE85":"Trang web từ xa yêu cầu một phiên mới (và plugin UpgradeSession không được tải). Đăng xuất và thử lại ",
"PE86":"Your account is locked. You must wait 30s before authenticate again",
"PE86":"Your account is locked. You have to wait",
"PE87":"You must authenticate again to access to Portal",
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
"PE89":"Truy cập không được cấp trên dịch vụ SAML",
@ -252,6 +252,7 @@
"rightsReloadNeedsLogout":"Tải lại quyền cần đăng xuất và đăng nhập lại",
"scope":"Phạm vi",
"search":"Search",
"seconds":"seconds",
"selectIdP":"Chọn bộ cung cấp danh tính của bạn",
"service":"Service",
"sendPwd":"Send me a link",

View File

@ -75,7 +75,7 @@
"PE83":"U2F verification failed. Retry or contact your administrator",
"PE84":"您没有授权访问该主机",
"PE85":"The remote site ask for a newer session (and UpgradeSession plugin isn't loaded). Logout and retry",
"PE86":"Your account is locked. You must wait 30s before authenticate again",
"PE86":"Your account is locked. You have to wait",
"PE87":"You must authenticate again to access to Portal",
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
"PE89":"Access not granted on SAML service",
@ -252,6 +252,7 @@
"rightsReloadNeedsLogout":"重新加载权限需要登出并且再次登录",
"scope":"Scope",
"search":"搜索",
"seconds":"seconds",
"selectIdP":"Select your Identity Provider",
"service":"服务",
"sendPwd":"发给我一个链接",

View File

@ -2,7 +2,11 @@
<div id="errorcontent" class="container">
<TMPL_IF AUTH_ERROR>
<div class="message message-<TMPL_VAR NAME="AUTH_ERROR_TYPE"> alert"><span trmsg="<TMPL_VAR NAME="AUTH_ERROR">"></span></div>
<div class="message message-<TMPL_VAR NAME="AUTH_ERROR_TYPE"> alert"><span trmsg="<TMPL_VAR NAME="AUTH_ERROR">"></span>
<TMPL_IF LOCKTIME>
<TMPL_VAR NAME="LOCKTIME"> <span trspan="seconds">seconds</span>.
</TMPL_IF>
</div>
</TMPL_IF>
<TMPL_IF RAW_ERROR>
<div class="message message-<TMPL_VAR NAME="AUTH_ERROR_TYPE"> alert"><span trspan="<TMPL_VAR NAME="RAW_ERROR">"></span></div>

View File

@ -109,7 +109,7 @@ ok(
);
ok(
$res->[2]->[0] =~
m%<div class="message message-negative alert"><span trmsg="82"></span></div>%,
m%<div class="message message-negative alert"><span trmsg="82"></span>%,
'Found "<span trmsg="82">"'
) or explain( $res->[2]->[0], '<span trmsg="82">' );
count(3);

View File

@ -112,7 +112,7 @@ ok(
);
ok(
$res->[2]->[0] =~
m%<div class="message message-negative alert"><span trmsg="93"></span></div>%,
m%<div class="message message-negative alert"><span trmsg="93"></span>%,
' PE93 found'
) or explain( $res->[2]->[0], "PE93 - Impersonation service not allowed" );
count(2);

View File

@ -111,7 +111,7 @@ ok(
);
ok(
$res->[2]->[0] =~
m%<div class="message message-negative alert"><span trmsg="93"></span></div>%,
m%<div class="message message-negative alert"><span trmsg="93"></span>%,
' PE93 found'
) or explain( $res->[2]->[0], "PE93 - Impersonation service not allowed" );
count(2);