BLOG | NGINX

Protección de URL con el módulo de enlace seguro en NGINX y NGINX Plus

NGINX - Parte de F5 - horizontal, negro, tipo RGB
Miniatura de Kunal Pariani
Kunal Pariani
Publicado el 29 de julio de 2016

Tanto el software de código abierto NGINX como NGINX Plus son muy seguros y confiables como servidores web, servidores proxy inversos y cachés para su contenido. Para obtener protección adicional contra el acceso de clientes no autorizados, puede usar directivas del módulo Secure Link para exigir que los clientes incluyan una cadena hash específica en la URL del activo que están solicitando.

En esta publicación de blog, analizaremos cómo configurar los dos métodos implementados en el módulo Enlace seguro. Los fragmentos de configuración de muestra protegen los archivos HTML y de listas de reproducción multimedia, pero se pueden aplicar a cualquier tipo de URL HTTP. Los métodos se aplican tanto a NGINX como a NGINX Plus, pero por razones de brevedad nos referiremos solo a NGINX Plus en el resto del blog.

Una descripción general de los métodos en el módulo de enlace seguro

El módulo Secure Link verifica la validez de un recurso solicitado comparando una cadena codificada en la URL de la solicitud HTTP con la cadena que calcula para esa solicitud. Si un enlace tiene una vida útil limitada y el tiempo ha expirado, el enlace se considera obsoleto. El estado de estas comprobaciones se captura en la variable $secure_link y se utiliza para controlar el flujo de procesamiento.

Como se mencionó, el módulo proporciona dos métodos. Sólo se puede configurar uno de ellos en un contexto http , servidor o ubicación determinado.

  • El primer modo, y más simple, se habilita mediante la directiva secure_link_secret . La cadena codificada es un hash MD5 calculado sobre la concatenación de dos cadenas de texto: la parte final de la URL y una palabra secreta definida en la configuración de NGINX Plus. (Para obtener detalles específicos sobre la primera cadena de texto, consulte Uso de URL seguras básicas ).

    Para acceder al recurso protegido, el cliente debe incluir el hash justo después del prefijo de la URL, que es una cadena arbitraria sin barras. En esta URL de ejemplo, el prefijo es videos y el recurso protegido es el archivo bunny.m3u8 :

    /videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8

    Un caso de uso para este método es cuando un usuario carga una imagen o un documento a un servidor para compartir, pero desea evitar que cualquiera que conozca el nombre del archivo acceda a él hasta que se publique el enlace oficial.

  • El segundo método, más flexible, está habilitado por las directivas secure_link y secure_link_md5 . Aquí la cadena codificada es un hash MD5 de variables definidas en el archivo de configuración NGINX Plus. Lo más común es incluir la variable $remote_addr para restringir el acceso a una dirección IP de cliente en particular, pero se pueden usar otros valores, por ejemplo $http_user_agent , que captura el encabezado User-Agent y, por lo tanto, restringe el acceso a ciertos navegadores.

    Opcionalmente, puede especificar una fecha de expiración después de la cual la URL ya no funcionará incluso si el hash es correcto.

    El cliente debe agregar el argumento md5 a la URL de solicitud para especificar el hash. Si se incluye una fecha de vencimiento en la cadena codificada, el cliente también debe agregar el argumento de vencimiento para especificar la fecha, como en esta URL de ejemplo para solicitar el archivo protegido pricelist.html :

    /files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740

El módulo Secure Link está incluido en los binarios NGINX de código abierto prediseñados de nginx.org , los paquetes NGINX proporcionados por los proveedores de sistemas operativos y en NGINX Plus . No se incluye de forma predeterminada cuando se compila NGINX desde la fuente; habilítelo incluyendo el argumento --with-http_secure_link_module en el comando de configuración .

Uso de URL seguras básicas

La forma más básica de proteger las URL es con la directiva secure_link_secret . En el siguiente fragmento de muestra, protegemos un archivo de lista de reproducción de medios de transmisión en vivo HTTP (HLS) llamado /bunny.m3u8 . Se almacena en el directorio /opt/secure/hls , pero se expone a los clientes que utilizan una URL que comienza con el prefijo videos .

servidor {
escuchar 80;
nombre_del_servidor demostración_de_enlace_seguro;

ubicación /videos {
secreto_de_enlace_seguro enigma;
si ($enlace_seguro = "") { devolver 403; }

reescribir ^ /seguro/$enlace_seguro;
}

ubicación /seguro {
interno;
raíz /opt;
}
}

Con esta configuración, para acceder al archivo /opt/secure/hls/bunny.m3u8 los clientes deben presentar la siguiente URL:

/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8

La cadena con hash viene justo después del prefijo, que es una cadena arbitraria sin barras (aquí, videos ).

El hash se calcula en una cadena de texto que concatena dos elementos:

  • La parte de la URL que sigue al hash, aquí hls/bunny.m3u8 .
  • El parámetro de la directiva secure_link_secret , aquí enigma .

Si la URL de solicitud del cliente no tiene el hash correcto, NGINX Plus establece la variable $secure_link en la cadena vacía. El si La prueba falla y NGINX Plus devuelve el 403 Prohibido Código de estado en la respuesta HTTP.

De lo contrario (lo que significa que el hash es correcto), la directiva de reescritura reescribe la URL; en nuestro ejemplo, /secure/hls/bunny.m3u8 (la variable $secure_link captura la parte de la URL que sigue al hash). Las URL que comienzan con /secure son manejadas por el segundo bloque de ubicación . La directiva raíz en ese bloque establece /opt como el directorio raíz para los archivos solicitados y la directiva interna especifica que el bloque se usa solo para solicitudes generadas internamente.

Generación del hash en el cliente para una URL básica segura

Para obtener el hash MD5 en formato hexadecimal que el cliente debe incluir en la URL, ejecutamos el comando openssl md5 con la opción -hex :

# echo -n 'hls/bunny.m3u8enigma' | openssl md5 -hex (entrada estándar)= 80e2dfecb5f54513ad4e2e6217d36fd4

Para obtener una discusión sobre cómo generar hashes mediante programación, consulte Generación del hash mediante programación .

Respuesta del servidor a URL básicas seguras

Los siguientes comandos curl de muestra muestran cómo responde el servidor a diferentes URL seguras.

Si la URL incluye el hash MD5 correcto, la respuesta es200 DE ACUERDO :

# curl -I http://demo-de-enlace-seguro/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8 | head -n 1 HTTP/1.1 200 OK

Si el hash MD5 es incorrecto, la respuesta es403 Prohibido :

# curl -I http://demo-de-enlace-seguro/videos/2c5e80de986b6fc80dd33e16cf824123/hls/bunny.m3u8 | head -n 1 HTTP/1.1 403 Prohibido

Si el hash de bunny.m3u8 se utiliza para un archivo diferente, la respuesta también es403 Prohibido :

# curl -I http://demo-de-enlace-seguro/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hs/oven.m3u8 | head -n 1 HTTP/1.1 403 Prohibido

Uso de URL seguras que expiran

El método más flexible para proteger URL utiliza las directivas secure_link y secure_link_md5 . En este ejemplo, los usamos para permitir el acceso al archivo /var/www/files/pricelist.html solo desde clientes en la dirección IP 192.168.33.14 y solo hasta el 31 de diciembre de 2016.

Nuestro servidor virtual escucha en el puerto 80 y maneja todas las solicitudes HTTP seguras bajo el bloque de ubicación / archivos , donde la directiva raíz establece / var / www como el directorio raíz para los archivos solicitados.

La directiva secure_link define dos variables que capturan argumentos en la URL de la solicitud: $arg_md5 se establece en el valor del argumento md5 y $arg_expires en el valor del argumento expires .

La directiva secure_link_md5 define la expresión que se codifica para generar el valor MD5 para la solicitud; durante el procesamiento de la URL, el codificado se compara con el valor de $arg_md5 . La expresión de muestra aquí incluye el tiempo de expiración transcurrido en la solicitud (capturado en la variable $secure_link_expires ), la URL ( $uri ), la dirección IP del cliente ( $remote_addr ) y la palabra enigma .

servidor {
escuchar 80;
nombre_del_servidor_demo_de_enlace_seguro;

ubicación /archivos {
raíz /var/www;
enlace_seguro $arg_md5,$arg_expires;
enlace_seguro_md5 "$enlace_seguro_expires$uri$dirección_remota enigma";

si ($enlace_seguro = "") { devolver 403; }
si ($enlace_seguro = "0") { devolver 410; }
}
}

Con esta configuración, para acceder a /var/www/files/pricelist.html , un cliente con dirección IP 192.168.33.14 debe enviar esta URL de solicitud antes del sábado 31 de diciembre de 2016 a las 23:59:00 UTC :

/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740

Si el hash en la URL enviada por el cliente (capturado en la variable $arg_md5 ) no coincide con el hash calculado a partir de la directiva secure_link_md5 , NGINX Plus establece la variable $secure_link en la cadena vacía. La prueba if falla y NGINX Plus devuelve el403 Código de estado prohibido en la respuesta HTTP.

Si los hashes coinciden pero el enlace ha expirado, NGINX Plus establece el $enlace seguro variable a 0;de nuevo el si La prueba falla, pero esta vez NGINX Plus devuelve el resultado. 410 Desaparecido Código de estado en la respuesta HTTP.

Generación del hash y el tiempo de expiración en un cliente

Ahora veamos cómo un cliente calcula los argumentos md5 y caduca para incluirlos en la URL.

El primer paso es determinar el equivalente en tiempo Unix de la fecha de expiración, porque ese valor está incluido en la expresión hash en forma de la variable $secure_link_expires . Para obtener la hora Unix (la cantidad de segundos desde Epoch (1970-01-01 00:00:00 UTC)) , utilizamos el comando date con la opción -d y el especificador de formato +%s .

En nuestro ejemplo, configuramos el tiempo de expiración en sábado 31 de diciembre de 2016 a las 23:59:00 UTC , por lo que el comando es:

# fecha -d "2016-12-31 23:59" +%s1483228740

El cliente incluye este valor como el argumento expires=1483228740 en la URL de la solicitud.

Ahora ejecutamos la cadena definida por la directiva secure_link_md5$secure_link_expires$uri$remote_addr enigma – a través de tres comandos:

  • El comando openssl md5 con la opción -binary genera el hash MD5 en formato binario.
  • El comando openssl base64 aplica codificación Base64 al valor hash.
  • Los comandos tr reemplazan el signo más ( + ) con el guion ( - ) y la barra ( / ) con el guión bajo ( _ ), y eliminan el signo igual ( = ) del valor codificado.

Para nuestro ejemplo, el comando completo es:

# echo -n '1483228740/files/pricelist.html192.168.33.14 enigma' | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d = AUEnXC7T-Tfv9WLsWbf-mw

El cliente incluye este valor como argumento md5=AUEnXC7T-Tfv9WLsWbf-mw en la URL de la solicitud.

Generando el hash programáticamente

Si su servidor web NGINX Plus sirve contenido dinámico desde un servidor de aplicação , tanto NGINX Plus como el servidor de aplicação deben usar la misma URL segura. Puede generar el hash para el argumento md5 en la URL mediante programación. La siguiente función Node.js genera un hash que coincide con el definido en el fragmento de configuración de NGINX Plus anterior. Toma un tiempo de expiración, una URL, una dirección IP del cliente y una palabra secreta como argumentos y devuelve el hash MD5 en formato binario codificado en Base64.

var crypto = require("crypto");

función generateSecurePathHash(caduca, url, ip_del_cliente, secreto) {
if (!caduca || !url || !ip_del_cliente || !secreto) {
devuelve indefinido;
}

var entrada = caduca + url + ip_del_cliente + " " + secreto;
var binaryHash = crypto.createHash("md5").update(input).digest();
var valorbase64 = new Buffer(binaryHash).toString('base64');
devuelve valorbase64.replace(/=/g, '').replace(/+/g, '-').replace(///g, '_');
}

Para calcular el hash de nuestro ejemplo actual, pasamos estos argumentos:

generateSecurePathHash(nueva fecha('12/31/2016 23:59:00').getTime()), '/files/pricelist.html', “192.168.33.14”, "enigma");

Respuesta del servidor a URL seguras con tiempos de expiración

Los siguientes comandos curl de muestra muestran cómo responde el servidor a las URL seguras.

Si un cliente con la dirección IP 192.168.33.14 incluye el hash MD5 y el tiempo de expiración correctos, la respuesta es200 DE ACUERDO :

# curl -I --interface "192.168.33.14" 'http://demo-de-enlace-seguro/archivos/lista-de-precios.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740' | head -n 1 HTTP/1.1 200 OK

Si un cliente con una dirección IP diferente envía la misma URL, la respuesta es403 Prohibido :

# curl -I --interface "192.168.33.33" 'http://secure-link-demo/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740' | head -n 1 HTTP/1.1 403 Prohibido

Si el valor hash del argumento md5 es incorrecto, la respuesta es403 Prohibido :

# curl -I --interface "192.168.33.14" 'http://secure-link-demo/files/pricelist.html?md5=qeUNjiY2FTIVMaXUsxG-7w&expires=1483228740' | head -n 1 HTTP/1.1 403 Prohibido

Si la URL ha expirado (la fecha representada por el argumento de expiración es del pasado), la respuesta es410 Desaparecido :

# curl -I --interface "192.168.33.14" 'http://secure-link-demo/files/pricelist.html?md5=Z2rNva2InyVcRTlhqAkT4Q&expires=1467417540' | head -n 1 HTTP/1.1 410 Ignorado

Ejemplo: Cómo proteger archivos de segmentos con fecha de vencimiento

Aquí hay otro ejemplo de una URL segura con fecha de vencimiento, utilizada para proteger tanto la lista de reproducción de un recurso multimedia como los archivos de segmento.

Una diferencia con el ejemplo anterior es que aquí agregamos un bloque de configuración de mapa para eliminar la extensión de la lista de reproducción (archivo .m3u8 ) y de los segmentos HLS (archivos .ts ) mientras capturamos el nombre del archivo en la variable $file_name , que se pasa a la directiva secure_link_md5 . Esto sirve para proteger las solicitudes de los segmentos .ts individuales así como de la lista de reproducción.

Otra diferencia con el primer ejemplo es que incluimos la variable $http_user_agent (que captura el encabezado User-Agent ) en la directiva secure_link_md5 , para restringir el acceso a clientes en navegadores web específicos (por ejemplo, para que la URL funcione en Safari pero no en Chrome o Firefox).

map $uri $nombre_archivo {
predeterminado ninguno;
"~*/s/(?<nombre>.*).m3u8" $nombre;
"~*/s/(?<nombre>.*).ts" $nombre;
}

servidor {
escuchar 80;
nombre_servidor secure-link-demo;

ubicación /s {
raíz /opt;
enlace_seguro $arg_md5,$arg_expires;
enlace_seguro_md5 "$enlace_seguro_expires$nombre_archivo$http_user_agent enigma";

si ($enlace_seguro = "") { devolver 403; }
si ($enlace_seguro = "0") { devolver 410; }
}
}

resumen

El módulo Secure Link de NGINX le permite proteger archivos contra acceso no autorizado agregando datos codificados como el hash de una parte específica de la URL. Agregar un tiempo de expiración también limita el tiempo de validez de los enlaces, para una seguridad aún mayor.

Para probar NGINX Plus, comience hoy su prueba gratuita de 30 días o contáctenos para analizar sus casos de uso.


"Esta publicación de blog puede hacer referencia a productos que ya no están disponibles o que ya no reciben soporte. Para obtener la información más actualizada sobre los productos y soluciones F5 NGINX disponibles, explore nuestra familia de productos NGINX . NGINX ahora es parte de F5. Todos los enlaces anteriores de NGINX.com redirigirán a contenido similar de NGINX en F5.com.