17 febrero 2014

[1/2] Seguridad en Redis - Fortificación

Si estás leyendo este artículo seguramente sea porque ya conoces Redis, un motor de base de datos basado en clave/valor que almacena los datos en memoria y que últimamente, debido al alto rendimiento que ofrece, está de moda.

En este artículo se detallarán medidas de seguridad a aplicar para asegurar su fortificación

En la mayoría de los sistemas Linux las instalaciones por defecto  ya tienen en consideración algunas de estas inquietudes, pero por requisitos o por instalaciones manuales en ocasiones son modificadas.

La propia documentación de Redis nos pone en aviso de que está diseñado pensando en los mundos de Yupi: "Redis is designed to be accessed by trusted clients inside trusted environments", algo extraño teniendo en cuenta que su autor es Salvatore Sanfilippo (antirez), al que conocemos de otros proyectos como hping 

1.- Escucha del servicio.
El demonio de redis debería escuchar únicamente en loopback o un socket de Unix. Si no, nuestro servicio será accesible a toda la red, por defecto, sin autenticación.

Para configurar las interfaces en las que escucha se debe modificar el fichero redis.conf y especificar las IPs en el parámetro bind y el puerto con el parámetro port, que en caso de ser 0, no permitirá conexiones TCP.

Tal y como comentaba inicialmente, esta configuración viene por defecto para 127.0.0.1 6379/tcp pero en ocasiones "pasan cosas", tal y como se puede ver en shodan 

port 6379
bind 127.0.0.1

En caso de que sea necesario el uso por red, es conveniente filtrar el puerto mediante un firewall en local.

# 6379 = redis port
# 10.1.2.3 = clientIP1
iptables -I INPUT -p tcp --dport 6379 -s 10.1.2.3 -j ACCEPT
iptables -I OUTPUT -p tcp --sport 6379 -d 10.1.2.3 -j ACCEPT
iptables -I INPUT -p tcp --dport 6379 -j DROP

Para habilitar el socket de unix se especifica mediante los siguientes valores.

unixsocket /var/run/redis/redis.sock
unixsocketperm 755

2.- Ejecución con los mínimos privilegios.
El servicio debe arrancarse bajo un usuario no privilegiado específico y si es posible, en un entorno enjaulado. Como veremos en el siguiente artículo esto puede volverse uno de los mayores problemas.

El cambio de usuario implica que los ficheros que utiliza el motor sean también propiedad de este usuario. Como son el fichero de PID (especificado mediante pidfile en redis.conf), el log (logfile) y los directorios de la base de datos (dir).

En caso de Ubuntu todos estos parámetros de arranque están en el propio script de inicio: /etc/init.d/redis-server, al igual que en CentOS: /etc/rc.d/init.d/redis

En general, estos parámetros también deben estar así si se instala un paquete, aunque por desgracia si se desea enjaular será necesario hacerlo manualmente.

pidfile /var/run/redis/redis-server.pid
logfile /var/log/redis/redis-server.log
dir /var/lib/redis

3.- Establecer autenticación. 
Este punto es crítico, ya que por defecto se puede acceder a la base de datos sin ningún tipo de autenticación. El acceso es total y permite ejecutar absolutamente todos los comandos de la base de datos.

Para establecer autenticación se debe especificar una contraseña (en texto claro) con el parámetro requirepass en el archivo redis.conf 

Redis no soporta usuarios ni roles, por lo que aquel que conecte tendrá todo o nada.

requirepass SuperInfinitoOOoOOoOO

Si la base de datos se replica, los esclavos deben de definir esta contraseña en su configuración.

masterauth SuperInfinitoOOoOOoOO

4.- Desactivar los comandos no usados.
La base de datos soporta decenas de comandos distintos. Algunos de ellos completamente innecesarios para el funcionamiento normal de la base de datos y mucho menos, para usuarios que no deberían tener privilegios de administración (como los desarrolladores).

Para desactivar un comando se renombra a "" (nada) y dejará de ser posible su uso. También se puede renombrar a algo desconocido para que solo aquellos que lo conozcan puedan hacer uso de la llamada.

Lo ideal es identificar los comandos que son necesarios y deshabilitar el resto, son especialmente peligrosos: FLUSHDB, FLUSHALL, CONFIG, DEBUG, MIGRATE, SLAVEOF y SHUTDOWN, Este último es usado para parar el servicio por los scripts de inicio y que por lo tanto requerirá que estos se modifiquen.

La lista completa de comandos se encuentra en: http://redis.io/commands

rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command DEBUG ""
rename-command SHUTDOWN SHUTDOWNSECRET
rename-command CONFIG ""
rename-command MIGRATE ""
rename-command SLAVEOF ""
rename-command CLIENT ""
... otros rename-command ...

5.- Cifrado de tráfico entre cliente y servidor.
La comunicación entre cliente y servidor es en texto plano y nativamente no es posible aplicar ningún tipo de cifrado en esta conexión. Si la red no es confiable (ninguna lo es) se debe utilizar una segunda herramienta sobre la que delegarlo. Existen múltiples opciones como stunnel, socat o ssh.

# cliente
stunnel -c -d 6379 -r servidor_redis:1999
# servidor
stunnel -d 1999 -r localhost:6379 

6.- Almacenamiento  de registros.
Los ficheros de registro deben salvaguardarse en un directorio seguro. Estos archivos deben rotarse y mantener la misma política de seguridad que para otros registros del sistema. Si no se define logfile serán mandados a la salida estandar del sistema. Si el parámetro daemonize está activado, serán enviados a /dev/ null.

loglevel notice
logfile /var/log/redis/redis-server.log

Si fuera necesario, existe la posibilidad de mandar los ficheros a syslog.

syslog-enabled yes
syslog-ident redis
syslog-facility local0

7.- Ajustes de rendimiento.
Como comentábamos inicialmente redis está diseñado pensando en el rendimiento, por ese motivo cambiar ajustes que afecten a este aspecto es un problema importante. Desgraciadamente, obtener el máximo rendimiento y ser susceptible a una denegación de servicio abusando de los recursos de memoria o red suelen ir de la mano.

Para ajustar esta línea, se debe jugar con varios parámetros que permitirán que el servicio permanezca estable y siga siendo óptimo en su rendimiento. De momento no existe una fórmula mágica para definirlos, dependerá de las especificaciones hardware de los servidores, número de peticiones y otros factores.

maxclients XXXX
timeout XXX
tcp-keepalive XXX
maxmemory XXXXXXXXX

Referencias:

6 comments :

Madrikeka dijo...

Gracias por la info, la verdad que me viene muy bien para mis futuros planes!! :D

Alejandro Ramos dijo...

El de mañana, que es de romper, es el divertido 8-)

rupia dijo...

¡Me encanta el post de hoy! Es de los de guardar :)
Y acabo de leer que el de mañana va a ser más diver :? :D

cipi dijo...

Qué manía tiene esta gente de guardar todo! Siempre tuve la esperanza de que estas cosas, en algún momento, mueriesen. Porque muera el servicio, porque decidan reutilizar almacenamiento... pero creo que estoy siendo un poco ilusa :/

cipi dijo...

s/mueriesen/muriesen

masticover dijo...

jajaja llevas razón, más seguro era XD


Gracias a tí.