Le logiciel open source NGINX et NGINX Plus sont tous deux très sûrs et fiables en tant que serveurs web, proxys inverses et caches pour votre contenu. Pour renforcer la protection contre les accès de clients non autorisés, vous pouvez utiliser les directives du module Secure Link afin d’exiger que les clients incluent une chaîne hachée spécifique dans l’URL de la ressource demandée.
Dans cet article de blog, nous verrons comment configurer les deux méthodes proposées par le module Secure Link. Les exemples d’extraits de configuration protègent les fichiers HTML et les fichiers de listes de lecture multimédias, mais peuvent s’appliquer à tout type d’URL HTTP. Ces méthodes s’appliquent aussi bien à NGINX qu’à NGINX Plus, mais, par souci de concision, nous ne mentionnerons que NGINX Plus dans la suite de cet article.
Présentation des méthodes du module Secure Link
Le module Secure Link vérifie la validité d’une ressource demandée en comparant une chaîne encodée dans l’URL de la requête HTTP à la chaîne qu’il calcule pour cette requête. Si un lien a une durée de vie limitée et que celle-ci a expiré, le lien est considéré comme obsolète. Le résultat de ces vérifications est enregistré dans la variable $secure_link et utilisé pour contrôler le déroulement du traitement.
Comme indiqué précédemment, le module propose deux méthodes. Une seule d’entre elles peut être configurée dans un contexte http, server ou location donné.
- Le premier mode, qui est aussi le plus simple, est activé par la directive
secure_link_secret. La chaîne encodée est un hachage MD5 calculé à partir de la concaténation de deux chaînes de texte : la partie finale de l’URL et un mot secret défini dans la configuration de NGINX Plus. (Pour plus de détails sur la première chaîne de texte, consultez Utilisation d’URL sécurisées de base.) Pour accéder à la ressource protégée, le client doit inclure le hachage juste après le préfixe de l’URL, qui est une chaîne arbitraire ne contenant aucune barre oblique. Dans cet exemple d’URL, le préfixe est videos et la ressource protégée est le fichier bunny.m3u8 : /videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8 Cette méthode peut notamment être utilisée lorsqu’un utilisateur téléverse une image ou un document sur un serveur afin de le partager, mais souhaite empêcher toute personne connaissant le nom du fichier d’y accéder avant la publication du lien officiel. - La seconde méthode, plus flexible, est activée par les directives
secure_linketsecure_link_md5. Ici, la chaîne encodée est un hachage MD5 de variables définies dans le fichier de configuration de NGINX Plus. Le plus souvent, la variable$remote_addrest incluse afin de restreindre l’accès à une adresse IP cliente particulière, mais vous pouvez utiliser d’autres valeurs, par exemple$http_user_agent, qui récupère l’en-têteUser-Agentet restreint ainsi l’accès à certains navigateurs. Vous pouvez également spécifier une date d’expiration au-delà de laquelle l’URL ne fonctionne plus, même si le hachage est correct. Le client doit ajouter l’argument md5 à l’URL de la requête pour spécifier le hachage. Si une date d’expiration est incluse dans la chaîne hachée, le client doit également ajouter l’argument expires pour spécifier cette date, comme dans cet exemple d’URL permettant de demander le fichier protégé pricelist.html : /files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740
Le module Secure Link est inclus dans les binaires open source précompilés de NGINX provenant de nginx.org, dans les paquets NGINX fournis par les éditeurs de systèmes d’exploitation, ainsi que dans NGINX Plus. Il n’est pas inclus par défaut lorsque vous compilez NGINX à partir du code source ; activez-le en ajoutant l’argument --with-http_secure_link_module à la commande configure.
Utilisation d’URL sécurisées de base
La méthode la plus simple pour sécuriser les URL consiste à utiliser la directive « secure_link_secret ». Dans l’extrait d’exemple suivant, nous sécurisons un fichier de liste de lecture multimédia HTTP Live Streaming (HLS) nommé /bunny.m3u8. Il est stocké dans le répertoire /opt/secure/hls, mais est accessible aux clients via une URL commençant par le préfixe « videos ».
server {
listen 80;
server_name secure-link-demo;
location /videos {
secure_link_secret enigma;
if ($secure_link = "") { return 403; }
rewrite ^ /secure/$secure_link;
}
location /secure {
internal;
root /opt;
}
}Avec cette configuration, pour accéder au fichier « /opt/secure/hls/bunny.m3u8 », les clients doivent utiliser l’URL suivante :
/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8
La chaîne hachée vient juste après le préfixe, qui est une chaîne arbitraire ne contenant aucune barre oblique (ici, « videos »).
Le hachage est calculé à partir d’une chaîne de texte qui concatène deux éléments :
- La partie de l’URL qui suit le hash, ici « hls/bunny.m3u8 ».
- Le paramètre de la directive «
secure_link_secret», ici «enigma».
Si l’URL de la requête du client ne contient pas le hachage correct, NGINX Plus définit la variable « $secure_link » comme une chaîne vide. Le test « if » échoue et NGINX Plus renvoie le code d’état « 403 Forbidden » dans la réponse HTTP.
Dans le cas contraire (c’est-à-dire si le hachage est correct), la directive « rewrite » réécrit l’URL – dans notre exemple en /secure/hls/bunny.m3u8 (la variable $secure_link capture la partie de l’URL qui suit le hachage). Les URL commençant par /secure sont traitées par le second bloc location. Dans ce bloc, la directive « root » définit /opt comme répertoire racine des fichiers demandés, tandis que la directive « internal » indique que le bloc est utilisé uniquement pour les requêtes générées en interne.
Génération du hachage côté client pour une URL sécurisée de base
Pour obtenir le hachage MD5 au format hexadécimal que le client doit inclure dans l’URL, nous exécutons la commande « openssl md5 » avec l’option « -hex »:
# echo -n 'hls/bunny.m3u8enigma' | openssl md5 -hex(stdin)= 80e2dfecb5f54513ad4e2e6217d36fd4Pour en savoir plus sur la génération programmatique de hachages, consultez la section « Génération programmatique du hachage ».
Réponse du serveur aux URL sécurisées de base
Les exemples de commandes curl suivants montrent comment le serveur répond aux différentes URL sécurisées.
Si l’URL contient le hachage MD5 correct, la réponse est 200 OK :
# curl -I http://secure-link-demo/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8 | head -n 1HTTP/1.1 200 OKSi le hachage MD5 est incorrect, la réponse est « 403 Forbidden »:
# curl -I http://secure-link-demo/videos/2c5e80de986b6fc80dd33e16cf824123/hls/bunny.m3u8 | head -n 1HTTP/1.1 403 ForbiddenSi le hachage de « bunny.m3u8 » est utilisé pour un autre fichier, la réponse est également 403 Interdit :
# curl -I http://secure-link-demo/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hs/oven.m3u8 | head -n 1HTTP/1.1 403 ForbiddenUtilisation d’URL sécurisées avec expiration
La méthode la plus souple pour sécuriser les URL utilise les directives « secure_link » et « secure_link_md5 ». Dans cet exemple, nous les utilisons pour autoriser l’accès au fichier « /var/www/files/pricelist.html » uniquement aux clients ayant l’adresse IP 192.168.33.14, et ce jusqu’au 31 décembre 2016 inclus.
Notre serveur virtuel écoute sur le port 80 et traite toutes les requêtes HTTP sécurisées dans le bloc location /files, où la directive root définit /var/www comme répertoire racine des fichiers demandés.
La directive « secure_link » définit deux variables qui récupèrent les arguments dans l’URL de la requête : $arg_md5 prend la valeur de l’argument md5, et $arg_expires celle de l’argument expires.
La directive « secure_link_md5 » définit l’expression qui est hachée afin de générer la valeur MD5 de la requête ; lors du traitement de l’URL, le hachage est comparé à la valeur de $arg_md5. Dans cet exemple, l’expression comprend le délai d’expiration transmis dans la requête (enregistré dans la variable $secure_link_expires), l’URL ($uri), l’adresse IP du client ($remote_addr) et le mot « enigma ».
server {
listen 80;
server_name secure-link-demo;
location /files {
root /var/www;
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri$remote_addr enigma";
if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 410; }
}
}Avec cette configuration, pour accéder à /var/www/files/pricelist.html, un client dont l’adresse IP est 192.168.33.14 doit envoyer cette URL de requête avant le samedi 31 décembre 2016 à 23:59:00 UTC :
/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740
Si le hachage figurant dans l’URL envoyée par le client (capturé dans la variable $arg_md5) ne correspond pas au hachage calculé à partir de la directive secure_link_md5, NGINX Plus définit la variable $secure_link comme une chaîne vide. Le test if échoue et NGINX Plus renvoie le code d’état 403 Forbidden dans la réponse HTTP.
Si les hachages correspondent mais que le lien a expiré, NGINX Plus définit la variable « $secure_link » sur « 0 » ; là encore, le test « if » échoue, mais cette fois, NGINX Plus renvoie le code d’état 410 Gone dans la réponse HTTP.
Génération du hachage et de l’heure d’expiration sur un client
Voyons maintenant comment un client calcule les arguments « md5 » et « expires » à inclure dans l’URL.
La première étape consiste à déterminer l’heure Unix correspondant à la date d’expiration, car cette valeur est incluse dans l’expression hachée sous la forme de la variable « $secure_link_expires ». Pour obtenir l’heure Unix – le nombre de secondes écoulées depuis l’époque Unix (1970-01-01 00:00:00 UTC) –, nous utilisons la commande date avec l’option -d et le spécificateur de format +%s.
Dans notre exemple, nous définissons la date d’expiration au samedi 31 décembre 2016 à 23:59:00 UTC. La commande est donc la suivante :
# date -d "2016-12-31 23:59" +%s1483228740Le client inclut cette valeur en tant que paramètre expires=1483228740 dans l’URL de la requête.
Nous soumettons maintenant la chaîne définie par la directive secure_link_md5 – $secure_link_expires$uri$remote_addr enigma – à trois commandes :
- La commande «
opensslmd5» avec l’option «-binary» génère le hachage MD5 au format binaire. - La commande «
opensslbase64» applique un encodage Base64 à la valeur hachée. - Les commandes «
tr» remplacent le signe plus (+) par le trait d’union (-) et la barre oblique (/) par le trait de soulignement (_), et suppriment le signe égal (=) de la valeur encodée.
Dans notre exemple, la commande complète est la suivante :
# echo -n '1483228740/files/pricelist.html192.168.33.14 enigma' | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =AUEnXC7T-Tfv9WLsWbf-mwLe client inclut cette valeur dans l’URL de la requête en tant qu’argument md5=AUEnXC7T-Tfv9WLsWbf-mw.
Génération du hachage par programmation
Si votre serveur web NGINX Plus diffuse du contenu dynamique provenant d’un serveur d’applications, NGINX Plus et le serveur d’applications doivent utiliser la même URL sécurisée. Vous pouvez générer par programmation le hachage correspondant à l’argument md5 dans l’URL. La fonction Node.js suivante génère un hachage identique à celui défini dans l’extrait de configuration NGINX Plus ci-dessus. Elle prend comme arguments une date d’expiration, une URL, l’adresse IP du client et un mot secret, puis renvoie le hachage MD5 au format binaire encodé en Base64.
var crypto = require("crypto");
function generateSecurePathHash(expires, url, client_ip, secret) {
if (!expires || !url || !client_ip || !secret) {
return undefined;
}
var input = expires + url + client_ip + " " + secret;
var binaryHash = crypto.createHash("md5").update(input).digest();
var base64Value = new Buffer(binaryHash).toString('base64');
return base64Value.replace(/=/g, '').replace(/+/g, '-').replace(///g, '_');
}Pour calculer le hachage dans notre exemple actuel, nous transmettons les arguments suivants :
generateSecurePathHash(new Date('12/31/2016 23:59:00').getTime()), '/files/pricelist.html', “192.168.33.14”, "enigma");Réponse du serveur aux URL sécurisées avec date d’expiration
Les exemples de commandes curl suivants montrent comment le serveur répond aux URL sécurisées.
Si un client dont l’adresse IP est 192.168.33.14 fournit le hachage MD5 et la date d’expiration corrects, la réponse est 200 OK :
# curl -I --interface "192.168.33.14" 'http://secure-link-demo/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740' | head -n 1
HTTP/1.1 200 OKSi un client ayant une adresse IP différente envoie la même URL, la réponse est 403 Interdit:
# curl -I --interface "192.168.33.33" 'http://secure-link-demo/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740' | head -n 1HTTP/1.1 403 ForbiddenSi la valeur de hachage de l’argument « md5 » est incorrecte, la réponse est 403 Forbidden:
# curl -I --interface "192.168.33.14" 'http://secure-link-demo/files/pricelist.html?md5=qeUNjiY2FTIVMaXUsxG-7w&expires=1483228740' | head -n 1HTTP/1.1 403 ForbiddenSi l’URL a expiré (la date représentée par l’argument « expires » est passée), la réponse est 410 Gone :
# curl -I --interface "192.168.33.14" 'http://secure-link-demo/files/pricelist.html?md5=Z2rNva2InyVcRTlhqAkT4Q&expires=1467417540' | head -n 1HTTP/1.1 410 GoneExemple – Sécurisation des fichiers de segments avec une date d’expiration
Voici un autre exemple d’URL sécurisée avec une date d’expiration, utilisée pour protéger à la fois la playlist d’un contenu multimédia et les fichiers de segments.
Une différence par rapport à l’exemple précédent est que nous ajoutons ici un bloc de configuration map afin de supprimer l’extension de la playlist (fichier .m3u8) et des segments HLS (fichiers .ts) lorsque nous enregistrons le nom du fichier dans la variable $file_name, qui est transmise à la directive secure_link_md5. Cela permet de sécuriser les requêtes portant aussi bien sur les segments .ts individuels que sur la playlist.
Une autre différence par rapport au premier exemple est que nous incluons la variable « $http_user_agent » (qui récupère l’en-tête « User-Agent ») dans la directive « secure_link_md5 », afin de limiter l’accès aux clients utilisant certains navigateurs web (par exemple, pour que l’URL fonctionne dans Safari, mais pas dans Chrome ni Firefox).
map $uri $file_name {
default none;
"~*/s/(?<name>.*).m3u8" $name;
"~*/s/(?<name>.*).ts" $name;
}
server {
listen 80;
server_name secure-link-demo;
location /s {
root /opt;
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$file_name$http_user_agent enigma";
if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 410; }
}
}Résumé
Le module Secure Link de NGINX vous permet de protéger les fichiers contre les accès non autorisés en ajoutant des données encodées, telles que le hachage d’une partie spécifique de l’URL. L’ajout d’une date d’expiration permet également de limiter la durée de validité des liens, pour une sécurité encore accrue.
Pour essayer NGINX Plus, commencez dès aujourd’hui votre essai gratuit de 30 jours ou contactez-nous pour discuter de vos cas d’utilisation.
À propos de l’auteur

Articles de blog associés

Tendances actuelles des technologies cloud natives, de l’ingénierie de plateforme et de l’IA
Découvrez les principaux enseignements tirés des réponses à l’enquête annuelle F5 NGINX sur les dernières tendances en matière de technologies cloud natives, de sécurité, d’ingénierie de plateforme et d’IA.
Quels contrôleurs Ingress NGINX sont affectés par les vulnérabilités CVE-2022-4886, CVE-2023-5043 et CVE-2023-5044 ?
Lorsque de nouvelles CVE sont signalées, il est facile de ne plus savoir si elles concernent un outil de contrôleur Ingress NGINX particulier, car il existe plusieurs projets. Cet article présente les CVE et explique comment distinguer les différents projets de contrôleurs Ingress afin de dissiper toute confusion.
Votre API est-elle en temps réel ? Testez sa latence avec l’outil rtapi de NGINX
Votre API répond-elle aux requêtes en moins de 30 ms ? Si ce n’est pas le cas, il ne s’agit pas d’une API en temps réel offrant la faible latence exigée par la grande majorité des organisations. Mesurez la latence de votre API avec l’outil rtapi de NGINX et découvrez comment NGINX peut l’aider à offrir une réactivité en temps réel.

Un testeur d’expressions régulières pour NGINX et NGINX Plus
Le testeur d’expressions régulières (regex) pour NGINX et NGINX Plus vous évite de tâtonner en vous indiquant si une expression régulière utilisée dans un bloc location ou map correspond aux valeurs comme prévu. Il génère la configuration appropriée et affiche les valeurs des groupes de capture.
Caches partagés avec les clusters de cache NGINX Plus, partie 1
Optimisez la capacité de votre cache web en le répartissant entre plusieurs serveurs de cache web NGINX ou NGINX Plus. Découvrez comment procéder dans cet article.
Introduction aux microservices
Les microservices suscitent actuellement beaucoup d’intérêt. Cet article de blog est le premier d’une série de sept consacrée à la conception, au développement et au déploiement de microservices.