Secciones bajar

NGINX, modificaciones para contabilizar usuarios

Por RAÚL RIVERO (SOITU)
Actualizado 14-07-2008 09:51 CET

En el primer módulo que liberamos, meses atrás, añadimos al NGINX la funcionalidad de "limpiar" páginas HTML y pegar, tras el tag de BODY, un trozo de código que, como os contábamos, nosotros utilizamos para, entre otras cosas, incluir un píxel de contabilización que luego nos permite saber el número aproximado de usuarios únicos o, mejor dicho, de navegadores únicos

Ese píxel que realmente no tiene ningún truco, el típico GIF de 1x1, lo que usa por debajo son las cookies que ya soportaba el NGINX, con su módulo ngx_http_userid_filter_module. Lo que les hemos añadido es una firma y poder centralizar todo el proceso de autenticación bajo control del NGINX. Por pasos:

Firma de cookies

El módulo ngx_http_userid_filter_module ya soporta la inserción de cookies para poder identificar usuarios. Son cookies de las que se pueden sacar sus valores con el siguiente trozo de Perl:

sub decodeNGINXCookie {
my $cookie = shift;

my $decoded = decode_base64($cookie);
my $ip = join(".", unpack("C4", substr($decoded, 0, 4)));
my $ts = unpack("N", substr($decoded, 4, 4));
my $pid = unpack("N", substr($decoded, 8, 4));
my $counter = unpack("n", substr($decoded, 12, 2));

return ($ip, $timestamp, $pid, $counter);
}

Nosotros queríamos poder conocer la autenticidad de esas cookies, así que les hemos añadido una firma. Generando cookies de la forma:

<cookie_NGINX>#<firma_MD5_cookie>

Para ello, se define una frase de distorsión que permite firmar las cookies generadas:

userid_secretforsign "AquI! Puedes_poner LA-frase que 2 Quieras, 0K?";

Además, hemos añadido la posibilidad de que la cookie se genere con la propiedad httponly activa:

userid_httponly on;

En el momento en que el NGINX ve una cookie con la firma correcta, le pasa al backend el valor de cookie_NGINX en la variable de entorno IDUSR.

Autenticación de usuarios

Puesto que el NGINX, con esta modificación, ya es capaz de autenticar cookies, ¿por qué no hacer que autentique usuarios? Es decir, ¿podríamos abstraer completamente la autenticación de los usuarios y que a los backends ya les llegase resuelto? Pues sí :).

La segunda modificación añade más información a la cookie y hace que tenga la siguiente pinta:

<cookie_NGINX>#<firma_MD5_cookie>#<datos_adicionales>

Donde datos_adicionales tiene una estructura tal que:

<nombre_usuario>[#<datos_extra>]

O sea, aparecen dos nuevos campos:

  • El nombre de usuario o nickname a mostrar del usuario autenticado.
  • Datos extras que queramos almacenar para no tener que recuperarlos de ningún otro sitio.

¿Dónde está el truco? Es el NGINX el que se asegura de que la firma es correcta para esa cookie, más el nombre del usuario, más los datos extra. De forma que pasa al backend la variable de entorno NAMEUSR con el nombre de usuario. Ventajas:

  • El backend no tiene que preocuparse de la autenticación.
  • Con mirar la existencia de la varible NAMEUSR, sabe si está tratando un usuario autenticado y su nombre [de usuario].
  • Si necesita los datos_extra sólo tiene que extraerlos de la cookie pues sabe que esta está autenticada.

Logs

Lo único que nos queda, es hacer que el log del servidor almacene todas esas cookies para luego poder contarlas. Para ello hay que usar la variable $uid_got. Ejemplo:

log_format apachecombined '$remote_addr - $uid_got [$time_local] '
'"$request" $status $body_bytes_sent '
"$http_referer" "$http_user_agent"';

Implementación

Añadir esta funcionalidad al NGINX requirió tocar varios módulos:

  • Obviamente fue necesario cambiar en ngx_http_userid_filter_module.c la gestión de las cookies, generandolas firmadas (si el navegador del usuario no tenía ninguna válida en la petición) y autenticando las firmas (si el navegador ya tenía una).
  • También fue necesario añadir a ngx_http_proxy_module.c la funcionalidad de pasarle al backend las variables de entorno que transmitiesen el valor de la cookie y el nombre del usuario.

Fuera del NGINX queda la gestión de generar cookies de usuarios. Esto es así porque quedan involucrados procesos que entroncan con la gestión de usuario, contraseñas, formularios de alta, etc. Sin embargo, al final de todo ese proceso, generar en Perl una cookie que pudiera gestionar el NGINX se reduciría a algo tan simple como:

my $datosAdicionales = $nombreUsuario .
($datosExtra?'#'.$datosExtra:'');
my $cookieCompleta = $cookieNGINX . '#' .
generaMD5Cookie($cookieNGINX, $datosAdicionales) . '#' .
$datosAdicionales;

sub generaMD5Cookie {
my $cookieNGINX = shift;
my $datosAdicionales = shift;

return 0 if !$cookieNGINX;

my $ctx = Digest::MD5->new;
$ctx->add($cookieNGINX);
$ctx->add($fraseDistorsion);
$ctx->add($datosAdicionales);
if defined($datosAdicionales);

return $ctx->hexdigest;
}

Por último, para poder compilar el nuevo módulo hace falta la librería MD5.

Descarga de código fuente
MD5SUM 14-Jul-2008 09:38150 bytes
nginx-0.6.32-COOKIES-20080714.patch.bz2 14-Jul-2008 09:37 4935 bytes

Di lo que quieras

Aceptar

Si quieres firmar tus comentarios puedes iniciar sesión »

En este espacio aparecerán los comentarios a los que hagas referencia. Por ejemplo, si escribes "comentario nº 3" en la caja de la izquierda, podrás ver el contenido de ese comentario aquí. Así te aseguras de que tu referencia es la correcta. No se permite código HTML en los comentarios.

Di lo que quieras

Lo sentimos, no puedes comentar esta noticia si no eres un usuario registrado y has iniciado sesión.
Si ya lo estás registrado puedes iniciar sesión ahora.

Volver a met Volver a portada
subir Subir al principio de la página