Previous: Multiple Login Checking, Up: Authentication [Contents][Index]
Authentication probe is an attempt of a user to use other user’s account, by guessing his password. The obvious indication of an authentication probe is appearance of several consecutive authentication failures for the same user. Of course, if the intruder is given sufficient number of such probes he will sooner or later succeed in finding the actual password. The conventional method to prevent this from occurring is to keep failure counters for each user and to lock the account when its failure counter reaches a predefined limit. Notice that a legitimate user may fail (sometimes even several times in sequence) in entering his password, so two important points should always be observed. First, failure counters record the number of consecutive authentication failures and they are reset after each successive authentication. Secondly, the maximum number of allowed consecutive failures should be set sufficiently high.
The version 1.7 offers two ways for controlling authentication probes: using external programs and using special SQL queries.
To control authentication probes using external programs, use the
combination of Exec-Program-Wait and
Auth-Failure-Trigger. The program specified by
Auth-Failure-Trigger is executed each time an authentication
attempt failed. When both attributes are used together, the program
invoked by Auth-Failure-Trigger can update the failure
counter, and the one invoked by Exec-Program-Wait can compare
the counter value with the predefined limit and reject authentication
when both values become equal. Such approach is most useful in
conjunction with BEGIN profile.
Let’s suppose the program /sbin/check_failure accepts a user name and returns 1 if the failure counter for this user has reached maximum allowed value. Otherwise it returns 0 and clears the counter. Another program, /sbin/count_failure increases failure counter value for the given user name. Assuming our basic authentication type is ‘PAM’, the raddb/users file will look as follows:
BEGIN NULL
Exec-Program-Wait = "/sbin/check_failure %C{User-Name}",
Auth-Failure-Trigger = "/sbin/count_failure %C{User-Name}",
Fall-Through = Yes
DEFAULT Auth-Type = PAM
Service-Type = Framed-User,
Framed-Protocol = PPP
[… Other profiles …]
The BEGIN profile will be executed before any other profile.
It will add to the RHS Exec-Program-Wait and
Auth-Failure-Trigger attributes and then radiusd will
proceed to finding a matching profile (due to Fall-Through
attribute). When such profile is found, the user will be authenticated
according to the method set up by the profile’s Auth-Type
attribute. If authentication fails, /sbin/count_failure
will be called and the user name passed to it as the argument. Otherwise,
/sbin/check_failure will be invoked.
To complete the example, here are working versions of both programs.
Failure counters for each user name are kept in separate file in
/var/log/radius/fails directory. Both programs are written
in bash.
#! /bin/bash test $# -eq 1 || exit 1 MAXFAIL=8 REGDIR=/var/log/radius/fails if [ -r "$REGDIR/$1" ]; then read COUNT < "$REGDIR/$1" COUNT=$((COUNT+1)) else COUNT=1 fi echo $COUNT > "$REGDIR/$1" # End of /sbin/count_failure
#! /bin/bash
test $# -eq 1 || exit 1
MAXFAIL=8
REGDIR=/var/log/radius/fails
if [ -r "$REGDIR/$1" ]; then
read COUNT < "$REGDIR/$1"
if [ $COUNT -ge $MAXFAIL ]; then
echo "Reply-Message=\"Too many login failures. Your account is locked\""
exit 1
else
rm "$REGDIR/$1"
fi
fi
exit 0
# End of check_failure
Another way of controlling authentication probes is by using
SQL database to store failure counters. Two queries are
provided for this purpose in raddb/sqlserver file:
auth_success_query is executed upon each successful
authentication, and auth_failure_query is executed upon
each authentication failure. Both queries are not expected to return
any values. One obvious purpose of auth_failure_query would be to
update failure counters and that of auth_success_query would be
to clear them. The auth_query or group_query should then
be modified to take into account the number of authentication
failures.
The default SQL configuration GNU Radius is shipped with provides a working example of using these queries. Let’s consider this example.
First, we create a special table for keeping authentication failure counters for each user:
CREATE TABLE authfail ( # User name this entry refers to user_name varchar(32) binary default '' not null, # Number of successive authentication failures for this user count int, # Timestamp when this entry was last updated time datetime DEFAULT '1970-01-01 00:00:00' NOT NULL, # Create a unique index on user_name UNIQUE uname (user_name) );
The query auth_fail_query will increment the value of
count column for the user in question:
auth_failure_query UPDATE authfail \
SET count=count+1,time=now() \
WHERE user_name='%C{User-Name}'
The query auth_success_query will clear count:
auth_success_query UPDATE authfail \
SET count=0,time=now() \
WHERE user_name='%C{User-Name}'
Now, the question is: how to use this counter in authentication? The answer is quite simple. First, let’s create a special group for all the users whose authentication failure counter has reached its maximum value. Let this group be called ‘*LOCKED_ACCOUNT*’. We’ll add the following entry to raddb/users:
DEFAULT Group = "*LOCKED_ACCOUNT*",
Auth-Type = Reject
Reply-Message = "Your account is currently locked.\n\
Please, contact your system administrator\n"
which will reject all such users with an appropriate reply message.
The only thing left now is to rewrite group_query so that it
returns ‘*LOCKED_ACCOUNT*’ when authfail.count reaches its
maximum value. Let’s say this maximum value is 8. Then the following
query will do the job:
group_query SELECT user_group FROM groups \
WHERE user_name='%u' \
UNION \
SELECT CASE WHEN (SELECT count > 8 FROM authfail \
WHERE user_name='%u')
THEN '*LOCKED_ACCOUNT*' END
The default configuration comes with these queries commented out. It is up to you to uncomment them if you wish to use SQL-based control over authentication failures.
Notice the following important points when using this approach:
UNION. Earlier
versions of MySQL lacked this support, so if you run
MySQL make sure you run a reasonably new version (at least
4.0.18).
auth_failure_query and auth_success_query
assume the database already contains an entry for each user. So,
when adding a new user to the database, make sure to insert
an appropriate record into authfails table, e.g.
INSERT INTO authfail VALUES('new-user',0,now());
Previous: Multiple Login Checking, Up: Authentication [Contents][Index]