DNSSEC. Asegurando las respuestas de nuestro dominio. La práctica (II)

Validar tu implementación de DNSSEC

Si seguiste las indicaciones de mi post anterior, ahora tendrás tu dominio bajo DNSSEC. En este momento es vital que te asegures de que todo está correcto, ya que si tu dominio «anuncia» (mediante la publicación de un registro DS en el registrador) que soportas DNSSEC, pero la implementación es errónea (claves no corresponden al DS, firmas caducadas, …) tu dominio dejará de ser visible para aquellos que usen DNSSEC (que cada día serán más). Es decir, adiós a tu correo, tu web, etc…

Para comprobar que todo está OK podemos usar servicios web como:

  • http://dnssec-analyzer.verisignlabs.com/ Que lista todos los pasos para validar el soporte DNSSEC de tu dominio.
  • http://dnsviz.net/ Que visualiza la relación (firmas) entre las claves desde el dominio raíz hasta el tuyo. Además de comprobar que está correcto, ayuda a entender la relación entre los diferentes (sub-)dominios y sus claves.

Si somos más de consola, los siguientes comandos nos permitirán comprobar que nuestro dominio valida correctamente:

## Primero guardamos las claves (KSK y ZSK) de la zona raíz (.)
$ dig . DNSKEY | grep -Ev '^($|;)' > root.keys

## Luego hacemos la validación de la cadena completa (desde la raíz
## hasta nuestro dominio)
$ dig +sigchase +trusted-key=./root.keys inittab.net. SOA

Autopsia de un registro DNSSEC

Una vez seguros de que nuestra configuración de DNSSEC es correcta, nos queda un asunto que tratar… el periodo de validez de la zona firmada! Como comenté en el post anterior, la zona se firma para un periodo de tiempo limitado, por defecto 30 días. Es necesario por tanto volver a firmar antes de que caduque, ya que en caso contrario… adiós web, correo, etc… Veamos un ejemplo de registro firmado:

inittab.net. 21569 IN A 91.121.65.176 
inittab.net. 21569 IN RRSIG A 14 2 21600 20150521144640 20150421144640 34840 inittab.net. uY8......

Primero vemos el RR de tipo A para inittab.net (la IP a la que apunta). Y luego tenemos el RR de tipo RRSIG (Resource Record SIGnature) que le acompaña permitiendo verificar la validez del RR de tipo A. Analicemos los campos del RRSIG:

Después de IN RRSIG, encontramos el tipo de registro al que se refiere. En este caso: A. Luego sigue el algoritmo con el que está firmado 14 (ECDSAP384SHA384). El 2 indica el número de etiquetas (net e inittab). Si fuera para un nombre tipo foo.bar.inittab.net. el valor sería 4. Detrás tenemos el TTL original, 21600. El siguiente campo es el más relevante para tema que nos preocupa, la fecha de caducidad de la firma 2015052114464021 de mayo de 2015, a las 9 de la noche (UTC). Antes de esa fecha deberemos volver a firmar la zona o las respuestas de nuestro DNS serán interpretadas como inválidas. La siguiente fecha indica cuando se realizó la firma del registro 21 de abril de 2015, y con que clave (ZSK en este caso) se hizo, 34840 de inittab.net. Por último estará la firma propiamente dicha.

Automatizando el proceso de firma

Ya sabemos cuando caducan las firmas de nuestra zona, 2015-05-21-14:46:40 en este ejemplo. Sólo queda automatizar el proceso de mantener las firmas vigentes. Para ello podemos usar los comandos del paquete dnssec-tools, o un par de sencillos shell scripts. El primero (check_rrsig), de Hauke Lampe, comprueba la fecha de caducidad de las firmas y el segundo, de un servidor, firma la zona en caso de que sea necesario:

#!/bin/bash
## (c) 2015 Alberto González Iniesta. GPLv2
## Depends: /usr/local/bin/check_rrsig

## Configuración
#DOMINIOS="foo.com bar.net baz.org"
DOMINIOS="inittab.net"

SERVIDOR_DNS=localhost
DIR_ZONAS="/etc/bind"
DIR_CLAVES="${DIR_ZONAS}/keys"
##

SALIDA=0

renueva_firma() {
  echo -n "Renovando $1 .."
  cd "$DIR_ZONAS"
  SERIE_ACTUAL=$( dig +short @$SERVIDOR_DNS $1 soa | awk '{print $3}' )
  (( SERIE_NUEVO = SERIE_ACTUAL + 1 ))
  rndc freeze # por si la zona es dinámica
  SERIE_EN_FICHERO=$( cut -d';' -f1 $1 | awk 'BEGIN {ORS=" "} /SOA.*\(/,/\)/ ' | tr '\t' ' ' | tr -s ' ' | cut -d'(' -f2 | awk '{print $1}' )
  sed -i "s/$SERIE_EN_FICHERO/$SERIE_NUEVO/" $1
  dnssec-signzone -d "$DIR_ZONAS" -K "$DIR_CLAVES" -S -t -u -3 $( dd if=/dev/random bs=16 count=1 2>/dev/null | hexdump -e \"%08x\" ) -o $1 "${DIR_ZONAS}/$1"
  rndc thaw # por si la zona es dinámica
  if rndc reload > /dev/null 2>&1 ; then
    echo "OK"
  else
    echo "ERROR"
    SALIDA=1
  fi
}

for DOMINIO in $DOMINIOS ; do
  OUTPUT=$( /usr/local/bin/check_rrsig -n $SERVIDOR_DNS -z $DOMINIO -w +10days )
  [ $? -eq 0 ] || renueva_firma $DOMINIO
done

exit $SALIDA

Una entrada en cron para que se ejecute todos los días y listo!. El script supone que los ficheros de zona se llaman como el ORIGIN (dominio), es decir para el dominio inittab.net el fichero se llama inittab.net, y supone que está en /etc/bind. Así como que las claves se encuentran en /etc/bind/keys. Sin duda es mejorable y se aceptan parches. Pero si lo hago de esta manera es porque para aprender siempre es mejor usar el mínimo de magia. Un día migraré a dnssec-tools, que entre otras cosas gestiona el cambio (rotación) de claves (KSK y ZSK), proceso que habría que hacer con cierta periodicidad. Pero si has llegado hasta aquí ya tienes una base de DNSSEC para seguir solito 🙂

NSEC vs NSEC3. Evitando la enumeración de zona

Para tener un sistema seguro de DNS es necesario firmar respuestas negativas, evitando que alguien pueda negar la existencia de un registro por ti. Es decir, con DNSSEC una respuesta que indique que un registro no existe, también tiene que venir firmada.

No se puede firmar siempre lo mismo, es decir no se puede firmar un texto que diga «eso no existe«, ya que una respuesta negativa podría ser usada por un atacante para negar la existencia de registros que si existen (enviando la respuesta firmada «eso no existe» a un cliente). Véase Replay Attack

Tampoco podemos generar una firma por cada registro no existente, por ejemplo firmar «estonoexiste.inittab.net y estotampoco.inittab.net y …. ya que el coste computacional (firmar miles de preguntas sobre registros no existentes) sería enorme, además de requerir la clave (ZSK normalmente) en todos los servidores de la zona (el primario y todos los secundarios). Mucha exposición para la clave.

NSEC al rescate. Se ordenan los registros de la zona en orden alfabético y se crear un registro NSEC por cada dos registros consecutivos. Esto permite devolver un registro NSEC (con su correspondiente RRSIG) por cualquier pregunta al DNS de algo que no exista entre los dos registros que cubre el NSEC. Es decir, si tenemos bar.inittab.net, foo.inittab.net y nada entre ellos, habrá un registro NSEC con esta forma:

bar.inittab.net. NSEC foo.inittab.net. A RRSIG NSEC

Que se devolverá cuando se pregunte por cochino.inittab.net o demente.inittab.net o eclectico.inittab.net. El problema de NSEC es que permite enumerar la zona completa. Es decir, preguntando por entradas no existentes podemos ir obteniendo los registros existentes mediantes las respuestas NSEC. Y podrían desvelarse registros «no públicos», tipo desarrollo.inittab.net, que aunque el DNS no garantiza que sean secretos, con este sistema sería trivial descubrirlos.

Para evitar este problema se crea NSEC3. La idea es más o menos la misma, pero con un cambio importante. Primero se hace un hash de todas las entradas de la zona y son estos hash los que se ordenan y los que componen una respuesta NSEC3:

LCFQO0AOA1QL3Q7A8E0ONQ9T2PTRLFS3.inittab.net. 86400 IN NSEC3 1 0 10 874201500AC7C3CFDAB802EDD07EEFFD ( VPE6NRVJK9AI2SUFEJG8I0G36C1ANBGS CNAME RRSIG )

NSEC3 no evita, mediante ataques por fuerza bruta/diccionarios, que se termine por enumerar la zona. Pero lo hace bastante más complejo, sobre todo si se usan salts aleatorias (en el ejemplo anterior el campo que empieza por 87420….). De ahí las opción -3 y los dd/hexdump en el comando dnssec-signzone recomendado en éste y el anterior post. De hecho ya hay planes de un NSEC5 que solvente la posible enumeración con NSEC3

$ exit

9 comentarios en “DNSSEC. Asegurando las respuestas de nuestro dominio. La práctica (II)

  1. javier

    que tal amigo excelente post precisamentando algo similar, crees que sea posible firmar N numero de zonas con las misma llaves KSK y ZSK. o bien de deberan crear las llaves KSK y ZSK para cada N numero de zonas? alguna sugerencia amigo saludos

    Responder
  2. Roberto

    Hola, muy buenos los dos tutoriales, te felicito por el esfuerzo.

    Pero ahora quiero preguntarte que sucede si tengo un DNS primario y ottro secundario: hay que hacer todo esto mismo que vos explicaste en los dos servidores, en mi caso ambos BIND 9.10 ???

    Muchas gracias.

    Responder
    1. Agnel

      perdon por el comentario anterior mal formado este es el detalle que me esta pasando la olla

      /usr/local/bin/check_rrsig: No such file or directory

      Responder
  3. Ruben

    Buena tarde.

    Estoy tratando de encontrar el comando en donde se muestre la siguiente salida:
    no valid RRSIG resolving

    Esto cuando el DNS tenga configurado el protocolo DNSSEC, pero el dominio no.

    De ante mano muchas gracias por su apoyo.

    Saludos

    Responder
    1. Alberto Gonzalez Iniesta Autor

      Hola, Rubén. Ese error lo podrías ver en los logs de un DNS que intentara resolver el dominio. También puedes usar el comando dig para ver si la respuesta está correctamente firmada, como se comenta en el artículo. En cualquier caso supongo que lo mínimo es que tengas el registro «DS» informado en el registrador del dominio, lo que indicaría que la respuesta debería ir firmada. Saludos!

      Responder

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *