Andrés Gómez
Abril 2013
En una red que necesite
controlar de forma segura el acceso de clientes, es aconsejable la
gestión centralizada de la autenticación de los mismos. Para ello
existe el protocolo
RADIUS (
acrónimo
en
inglés
de
Remote Authentication
Dial-In User
Server).
En general radius trabaja
en 3 procesos, como protocolo AAA. En seguridad informática, el
acrónimo AAA corresponde a un tipo de protocolos que realizan
tres funciones: Autenticación, Autorización y Contabilización
(Authentication, Authorization and Accounting en inglés). La
expresión protocolo AAA no se refiere pues a un protocolo en
particular, sino a una familia de protocolos que ofrecen los tres
servicios citados. (Fuente: Wikipedia)
Freeradius es uno de los
más populares servidores Radius, y es totalmente software libre
(licencia GPL v2).
No voy a detallar como
instalar freeradius en una plataforma Linux, ya que hay un excelente
tutorial de como hacerlo y además dejarlo funcional con una base de
datos MySQL (base de los usuarios y de parámetros de configuración
de las sesiones) y una interfaz gráfica web para la gestión del
mismo:
Con ese buen tutorial
quedará funcional el servidor básico, puede ser lo suficiente que
necesiten. Me voy a referir a temas de un nivel intermedio que he
tenido que personalizar, como son Contadores SQL, accesos simultáneos
y restricción de caracteres prohibidos en nombres de usuarios.
CONTADORES SQL
Los contadores SQL son
mecanismo que ya trae el Freeradius (por defecto desactivados) que
permite correr ciertas consultas SQL luego de la autorización de un
usuario y que permite devolver parámetros al NAS (Servidor de acceso
a la red, que usualmente es un router) para que alimente ciertos
parámetros contenidos en los Diccionarios de parámetros que
entiende cada NAS y que aunque muchos son parámetros estándar,
otros dependen de marcas de equipos. Por ejemplo el contador lo usé
para hacer perfiles de navegación (clientes que podian acceder a la
red por 4 horas, 1 dia, 1 semana, etc.) y que en cada autenticación
calculara cuanto tiempo le quedaba disponible, y luego inhabilitara
el acceso de dicho usuario cuando se había acabado su tiempo.
Si se sigue el tutorial
mencionado ya se debió haber habilitado el uso de la base de datos
ya en el archivo /etc/freeradius/sites-available/default se debe
descomentar la líneas
# See "Autorization
Queries" in sql.conf
sql
# See "Accounting
Queries" in sql.conf
sql
Y en
/etc/freeradius/sites-available/inner-tunnel
# See "Autorization
Queries" in sql.conf
sql
Luego, para habilitar los
contadores SQL, en el archivo /etc/freeradius/radiusd.conf
descomentar la linea
$INCLUDE sql/mysql/counter.conf
Los contadores estan en
el archivo
/etc/freeradius/sql/mysql/counter.conf
Para entender el
funcionamiento profundo de la base de datos es bueno leer la wiki de
freeradius, yo detallaré como usé la base de datos para la
autenticación de usuarios agrupados en grupos (perfiles).
La tabla radcheck
asocia usuarios y contraseña de usuario, ejemplo
USUARIO1 User-Password := PASSWORD1
La tabla radusergroup
asocia el usuario con un grupo
USUARIO1 GRUPO1 0
La tabla radacct
la usa Freeradius para registrar toda la actividad de cada usuario.
Así que lo que se hace
es crear la cantidad de usuarios deseados en la tabla radcheck y
luego asosiar cada usuario a un grupo. Los parámetros de
configuración de los perfiles se aplican a los grupos, no a los
usuarios, aunque si se puede hacer lo mismo con los usuarios
directamente.
La tabla radgroupcheck
es la que tendrá los parámetros que van a caracterizar el perfil.
En mi caso usé un parámetro estándar para todo NAS (en mi caso
routers) “Max-All-Session”
que especifica el máximo de SEGUNDOS que podrá estar conectado un
usuario. Así, si quiero tener un perfil de 1 mes de acceso, el
registro en dicha tabla será:
1MES Max-All-Session := 2592000
Donde 2592000 es la
cantidad de segundos que hay en 1 mes estándar (30 días).
Los contadores SQL lo que
hacen en mi caso es ejecutar una consulta SQL que finalmente obtendrá
una cantidad de segundos que al final se RESTAN de los segundos (en este ejemplo 2592000) que son autorizados para cada usuario del perfil. el resultado de esa resta es el tiempo en segundo autorizado para navegar en esa sesión.
LA estructura de un contador
es así:
sqlcounter noresetcounter {
counter-name = Max-All-Session-Time
check-name =
Max-All-Session
sqlmod-inst = sql
key =
User-Name
reset = never
reject = 1
query = "SELECT IFNULL( GREATEST((UNIX_TIMESTAMP(now()) -
UNIX_TIMESTAMP(acctstarttime)), SUM(acctsessiontime)), 1) FROM
radacct WHERE username = '%{%k}' LIMIT 1"
Reply-Message :=
"Tiempo de navegación alcanzado."
}
Donde se debe especificar
que se trabaja con la variable Max-All-Session, la clave de
evaluación es el User_Name.
El reset tiene un papel
importante. Si se pone reset = daily el contador se reseteará a
media noche. Entonces si el USUARIO1 agotó su tiempo de acceso el
dia de hoy, a partir de media noche podrá volver a acceder.
Yo uso el “reset =
never” para que un usuario que se acabó su tiempo de acceso nunca
más pueda volver a acceder.
El query es una expresión
en SLQ estándar, donde:
UNIX_TIMESTAMP( NOW() ) :
fecha y hora de AHORA en formato UNIX
UNIX_TIMESTAMP(acctstarttime):
fecha y Hora del primer login dle usuario, en formato UNIX
UNIX_TIMESTAMP(now()) -
UNIX_TIMESTAMP(acctstarttime): esta resta dará en segundos, cuanto
tiempo ha pasado desde el tiempo en que el usuario se logueó por
primera vez en el servidor, hasta ahora (now).
SUM(acctsessiontime) suma
la cantidad total de los registros del campo acctsessiontime (que
registra cuantos segundos duró conectado un usuario en cada sesión)
y así obtiene el total de tiempo que el usuario ha accedido a la
red.
GREATEST((UNIX_TIMESTAMP(now())
- UNIX_TIMESTAMP(acctstarttime)), SUM(acctsessiontime). Elige el
mayor valor entre la resta de AHORA con la hora del primer login del
usuario, o el total de tiempo que el usuario ha accedido.
Así toda la consulta
hace que el servidor ante cada autenticación evalúe cuanto tiempo
ha pasado entre el primer momento de autenticación y el momento
actual, el valor quedará en segundos; el Greatest se introduce para
eventos en el que varios usuarios acceden simultáneamente con el
mismo usuario; por ejemplo el USUARIO2 tiene asignado 1 semana de
navegación (2592000 segundos) y acceden varios usuarios al mismo
tiempo con USUARIO2, cada acceso independiente contará y será
probable que los 2592000 segundos se agoten antes de una semana.
Luego de definir los contadores, hay
que editar el archivo
/etc/freeradius/sites-available/default
En la parte final de la seccion
authorize escribir el nombre de los contadores, ejemplo
authorize
{
...
noresetcounter
dailycounter
monthlycounter
}
Reiniciar el servicio.
/etc/init.d/freeradius
restart
RECOMENDACION:
correr en modo de debugging
para poder identificar problemas.
freeradius -X
AUTENTICACION POR MAC
Solamente
hay que usar el parametro Calling-station-Id en la tabla radcheck
asociada al user, con la MAC en formato 00:11:22:33:44:55
No es autenticación automática, es un
filtro.
USUARIO1 Calling-Station-Id == 00:23:8B:7F:47:DD
LIMITAR ACCESO
SIMULTANEO
Para habilitar uso
simultaneo de una cuenta, X veces, hacer:
En
/etc/freeradius/sql/mysql/dialup.conf descomentar la linea del sript
que dice simul_count_query
En la base de datos en la
tabla radcheck (si es solo para un usuario) configurar el maximo de
sesiones:
USER1 simultaneous-Use := 1
En la base de datos, e la
tabla radgroupcheck (si es para todo un grupo) configurar el maximo
de sesione:
GRUPO1 simultaneous-Use := 1
donde 1, se peude
reemplazar por la cantidad de sesiones simultaneas por usuario.
Cómo opera? La línea
que se descomenta es una consulta SQL, así:
SELECT RadAcctId,
AcctSessionId, UserName, NASIPAddress, NASPortId, FramedIPAddress,
CallingStationId, FramedProtocol FROM `radacct` WHERE
UserName='5MNSWJ' AND AcctStopTime IS NULL
Lo que hace es contar
cuantas líneas en la tabla "raddacct" de la base de datos
tiene el campo "AcctStopTime" como "NULL" para
cierto USUARIO. Esto indica que hay una sesión activa y que aún no
se a cerrado. Así que el resultante de la consulta son la sesiones
activas para cada usuario.
Sin embargo este método tiene ciertos
problemas, ya que si por alguna razón (como reinicio del NAS o del
servidor FreeRadius) no se terminó correctamente la sesión, el
registro quedará de la misma forma incompleto, es decir con el campo
"AcctStopTime" como "NULL". Al ejecutar la
consulta se tendrán aparentes "sesiones activas" que según
la configuración "simultaneous-Use" de la tabla radcheck
inahilitarán la conexión del cliente.
Para información...
los scripts que permiten hacer verificación de usuario navegado, en
la tabla raddact son:
SELECT RadAcctId, AcctSessionId,
UserName, NASIPAddress, NASPortId, FramedIPAddress, CallingStationId,
FramedProtocol FROM `radacct` WHERE UserName='USUARIO1' AND
AcctStopTime IS NULL
SELECT COUNT(*) FROM `radacct` WHERE
UserName='USUARIO1' AND AcctStopTime IS NULL
CARACTERES PROHIBIDOS
Para inhabilitar
caracteres en el username hay 2 opciones:
- En el archivo
/etc/freeradius/sql/mysql/dialup.conf se describe la forma en que se
captura el username, por defecto está descomentada la línea:
sql_user_name =
"%{User-Name}"
unas cuantas líneas
antes está comentada una línea que hace referencia a los caracteres
permitidos y empieza asignando la variable "safe-characters".
Se puede copiar esta línea y pegarla debajo de la definicion del
username, para que quede así (es un ejemplo donde solo se habilitan
los caracteres en mayuscutas ABCDEF y se prohíben el resto):
sql_user_name =
"%{User-Name}"
safe-characters =
"ABCDEF"
Así el username solo
puede contener esos caracteres.
Si bien funciona, tiene
una consecuencia importante. Si se inhabilitan por este medio
caracteres como el : . veremos que no solamente la restricción
aplica al username sino a todos los datos que envía el cliente.
Entonces en la base de datos por ejemplo, la direccion MAC ya no
tendrá los : sino otros caracteres, lo mismo para con otros campos
como la direccion IP. Finalmente también se afecta los datos con que
responde el servidor al NAS y se tienen efectos como que el
SessionTimeLeft no es reconocido por el NAS y así lo clientes no
pueden saber cuanto tiempo de navegación les queda.
- Otra
opción es crear expresiones regulares "regex" en la rutina
de Autorización del Freeradius.
La rutina de
autorización (Authorize{}) desde la version 2.x del freeradius se
encuentra en /etc/freeradius/sites-available/default, allí es
posible crear scripts que validen la autorización de usuarios, o la
rechacen. Así que allí se puede ingresar un loop if que evalúe una
expresión regular.
Un ejemplo que invalida (reject) un usuario
que tenga espacios en blanco sería:
authorize { ##esta
linea ya existe en el archivo
if ("%{User-Name}"
=~ / /) {
reject
}
}
##esta linea ya existe en el archivo
o pueden ser
regex más estructuradas, por ejemplo que inhabilite usuarios con
espacios en blanco pero solo en el el inicio o fin del username:
if ( ("%{User-Name}"
=~ / $/) || ("%{User-Name}" =~ /^ /) ){
reject
}