Avoiding Brute Force attacks on rt-2-0-15

Hi there,

For RT2-0-15, there is no protection from brute force attacks on either
the user/pass combination or on the cookie-strings.

Here is a solution:
Exchange the webrt/autohandler script by the lines below to limit the
number of rejected logins to 10 per minute.
(And be sure, you have installed Cookie::Cookie from cpan)

I would appreciate comments.

Kind Regards
Andreas

Andreas Warnke
3SOFT GmbH, Frauenweiherst. 14, 91058 Erlangen
Tel.: +49-9131-7701-274 mailto:Andreas.Warnke@3SOFT.de
Fax: +49-9131-7701-333 http://www.3SOFT.de

%# $Header: /pro/CVS/rt/rt-2-0-15/webrt-rtee/autohandler,v 1.1
2002/11/07 10:59:31 anwa2219 Exp $
<& /Elements/Footer, %ARGS &>

<%INIT>

my $current_time = time;
$m->{‘rt_base_time’} = $current_time;

----------------------------------------

added by Andreas Warnke

‘Period’ denotes the end of the current observation interval

‘Attacks’ is the number of rejected login tries

during the current observation interval

----------------------------------------

my $ACache = $m->cache;
my $period = $ACache->get(‘Period’) || 0;
my $attacks = $ACache->get(‘Attacks’);

----------------------------------------

----------------------------------------

added by Andreas Warnke

Next observation interval?

(And initialization)

----------------------------------------

if ( $period < $current_time ) {
$period = $current_time + 60;
$attacks = 0;
$ACache->set(‘Period’,$period);
$ACache->set(‘Attacks’,$attacks);
}

----------------------------------------

----------------------------------------

added by Andreas Warnke

AttackEncountered?

----------------------------------------

sub AttackEncountered {
my $ACache = $m->cache;
my $attacks = $ACache->get(‘Attacks’);
$attacks += 1;
$ACache->set(‘Attacks’,$attacks);
}

----------------------------------------

#if it’s a noauth file, don’t ask for auth.
if ($m->base_comp->path =~ ‘^/+NoAuth/’) {
$m->call_next();
$m->abort();
}

----------------------------------------

added by Andreas Warnke

The complete database is locked

if there have been more than 10 attacks.

Q: Why not just disable the login-sequence

A: There are 2 types of brute force attacks:

1) Brute force on the user/pass combination

2) Brute force on a valid session cookie

So: Neither may be served if the system

is under attack

----------------------------------------

elsif ( $attacks > 10 ) {
$m->comp(’/Elements/Login’, Error => ‘Sorry. RT2 is locked for
60 seconds.’, %ARGS);
$m->abort();
}

----------------------------------------

----------------------------------------

deleted by Andreas Warnke

----------------------------------------

If RT is configured for external auth, let’s get REMOTE_USER

We intentionally don’t test for REMOTE_USER to meet our policy

#elsif ($RT::WebExternalAuth){

$user = $ENV{‘REMOTE_USER’};

$session{‘CurrentUser’} = RT::CurrentUser->new();

$session{‘CurrentUser’}->Load($user);

unless ($session{‘CurrentUser’}->id() ) {

delete $session{‘CurrentUser’};

$m->comp(’/Elements/Login’, %ARGS, Error=> 'You are not an

authorized user’);

$m->abort();

}

#}

----------------------------------------

If the user is loging in, let’s authenticate

elsif (defined ($user) && defined ($pass)){

$session{'CurrentUser'} = RT::CurrentUser->new();
$session{'CurrentUser'}->Load($user);
unless ($session{'CurrentUser'}->id() ) {
delete $session{'CurrentUser'};
AttackEncountered();
$m->comp('/Elements/Login', %ARGS, Error=> 'Your username or

password is incorrect’);
$m->abort();
};
unless ($session{‘CurrentUser’}->IsPassword($pass)) {
delete $session{‘CurrentUser’};
AttackEncountered();

$m->comp('/Elements/Login', Error => 'Your username or password

is incorrect’, %ARGS);
$m->abort();
}
}

#If we’ve got credentials, lets serve the file up.
if ( (defined $session{‘CurrentUser’}) and
( $session{‘CurrentUser’}->Id) ) {

# If the user isn\'t privileged, they can only see SelfService
if ((! $session{'CurrentUser'}->Privileged) and
($m->base_comp->path !~ '^/+SelfService/') ) {
$m->comp('/SelfService/index.html');
$m->abort();
}
else {
$m->call_next;
}

}

#If we have no credentials
else {
AttackEncountered();
$m->comp(’/Elements/Login’, %ARGS);
$m->abort();
}

</%INIT>

<%ARGS>
$user => undef
$pass => undef
</%ARGS>