Loading...

Sécurité · 9 min de lecture

URLs signées : des liens qui cessent de fonctionner

Une URL signée porte la preuve qu'elle a été émise par vous, et un moment où elle meurt. C'est le contrôle que vous voulez pour les fichiers que les gens paient. Ce guide couvre les deux familles d'URL signées, la recette exacte sur cdn.com.tr, et l'erreur de cache qui fait que chaque téléchargement protégé frappe votre origine.

Mis à jour

URLs signées : des liens qui cessent de fonctionner

Ce qu'une URL signée promet réellement

Trois choses, et il vaut la peine d'être précis, car les gens en attendent une quatrième.

Elle prouve que le lien vient de vous. La signature est un hash du chemin, de l'expiration et d'un secret que seul votre serveur connaît. Personne ne peut fabriquer un lien fonctionnel sans le secret.

Elle expire. L'expiration fait partie de ce qui est signé, donc elle ne peut pas être modifiée sans casser la signature.

Elle est vérifiée avant que votre origine ne soit touchée. En périphérie CDN, une requête non signée est refusée en périphérie ; votre serveur ne la voit jamais.

Ce qu'elle ne promet pas : que la personne qui a ouvert le lien ne sauvegardera pas le fichier et ne l'enverra pas par mail à un ami. Une URL signée contrôle l'accès à l'URL, pas aux octets. Si vous avez besoin d'un contrôle après le téléchargement, vous cherchez du DRM, qui est un produit différent et bien plus lourd.

Deux familles : signatures en périphérie et URLs pré-signées

Les signatures de chemin en périphérie — ce que vous donne un CDN. Votre application calcule une signature pour un chemin et une expiration ; la périphérie la vérifie à l'arrivée. Le fichier peut vivre n'importe où le CDN peut l'atteindre, et la vérification se fait près du visiteur.

Les URLs pré-signées du stockage d'objets — ce que vous donnent S3 et le stockage compatible S3. Le service de stockage lui-même émet une URL temporaire, signée avec votre clé d'accès, généralement valable quelques minutes. La signature voyage dans la chaîne de requête sous la forme X-Amz-Signature et ses compagnons.

Ce ne sont pas des concurrents. Un arrangement courant et sain consiste à mettre le stockage d'objets derrière un CDN, avec la signature de périphérie qui protège l'URL publique et le bucket gardé privé pour que personne ne puisse contourner la périphérie. Ce qu'il ne faut pas faire, c'est exposer une URL de stockage pré-signée directement au public en supposant que le CDN la protège — si le lien pointe vers le bucket, la périphérie n'est pas du tout dans le chemin.

Comment cela fonctionne sur cdn.com.tr

C'est un réglage sur une règle de diffusion, ce qui vous permet de protéger /downloads pendant que le reste du site reste public. Activez les liens expirants pour cette règle, définissez un secret, et générez des liens dans votre application.

La signature est la forme base64url du MD5 brut de trois éléments joints ensemble : l'expiration, le chemin, et le secret précédé d'une seule espace.

``` $uri = "/downloads/report.pdf"; $expires = time() + 600; // ten minutes $secret = "your-long-random-secret";

$token = rtrim(strtr(base64_encode( md5($expires . $uri . " " . $secret, true) ), "+/", "-_"), "=");

$url = "https://cdn.example.com{$uri}?md5={$token}&expires={$expires}"; ```

Trois résultats, et ils sont délibérément distincts pour que vos journaux puissent les différencier :

| Requête | Réponse | |---|---| | Signature valide, non expirée | le fichier, mis en cache normalement | | Aucune signature, ou une signature incorrecte | 403 | | Signature correcte, expiration dépassée | 410 |

Le 410 compte plus qu'il n'y paraît. Quand un client dit « votre lien est cassé », le code de statut à lui seul vous dit s'il a reçu un mauvais lien ou s'il a simplement trop attendu — sans avoir à lui demander quoi que ce soit.

Le piège de cache qui vous coûte le CDN

C'est la partie absente de la plupart des documentations, et c'est celle qui fait mal.

Chaque lien signé est unique : un md5 différent et un expires différent pour chaque visiteur et chaque émission. Si votre clé de cache inclut la chaîne de requête — ce qui est le défaut courant, et c'est le nôtre sauf si vous le changez — alors chaque requête signée est une entrée de cache distincte. Le taux de hit pour les fichiers protégés tombe à zéro, chaque téléchargement est récupéré depuis votre origine, et vous avez payé pour un CDN qui se comporte comme un simple proxy.

La correction est un seul réglage. Sur la règle de diffusion, définissez le mode de chaîne de requête pour que les paramètres de signature n'entrent pas dans la clé de cache :

- Liste d'ignorés — ignorez md5 et expires, gardez tout autre paramètre significatif. C'est le bon choix quand le même fichier est aussi récupéré avec de vrais paramètres. - Tout ignorer — l'option la plus simple quand les chemins protégés ne prennent aucun paramètre significatif, ce qui est généralement vrai pour les téléchargements.

Vérifiez-le après coup plutôt que de le supposer : demandez le même fichier deux fois avec deux signatures valides différentes et regardez l'en-tête de statut de cache. La seconde devrait être un hit. Si les deux sont des miss, la clé contient toujours la signature.

Choisir une expiration

Assez courte pour qu'un lien fuité soit sans valeur ; assez longue pour que le téléchargement se termine sur une mauvaise connexion.

Documents et images : de cinq à quinze minutes. Ils sont récupérés immédiatement après le clic.

Grosses vidéos et archives : d'une à six heures. Un fichier de deux gigaoctets sur une connexion mobile lente prend plus de temps que ce à quoi les gens s'attendent, et une expiration qui se déclenche en plein téléchargement produit un ticket de support qui ressemble à une corruption.

Les manifestes de streaming demandent de l'attention. Avec HLS, le lecteur récupère le manifeste puis de nombreux segments sur toute la durée de la lecture. Si vous signez chaque segment avec une expiration courte, la lecture se casse en plein milieu d'une longue vidéo. Signez avec une expiration qui couvre toute la session, ou signez le manifeste et laissez les segments protégés par un autre contrôle.

Une chose que vous ne pouvez pas faire, c'est révoquer un seul lien émis. Il est valide jusqu'à son expiration, un point c'est tout. Si vous avez besoin d'une révocation immédiate, faites tourner le secret — ce qui invalide tous les liens que vous avez émis.

Les erreurs qui font fuiter le secret

Signer dans le navigateur. Si le secret est en JavaScript, il est public. La signature appartient au serveur, toujours. Cela paraît évident et c'est pourtant la façon la plus courante dont les secrets s'échappent.

Figer les liens au moment du build. Un lien généré pendant un build statique porte une expiration fixée au moment du build, et il expire pendant que la page est encore en ligne. Générez-le au moment de la requête, ou via un petit endpoint qui redirige.

Le décalage d'horloge. L'expiration est comparée à l'horloge de la périphérie. Si votre serveur d'application a plusieurs minutes de retard, les liens naissent déjà expirés. Gardez NTP actif ; quand un lien échoue immédiatement après son émission, vérifiez l'horloge avant le code.

Mettre le secret dans un dépôt. Traitez-le comme un identifiant : variable d'environnement, pas de contrôle de version. Quand quelqu'un quitte l'équipe, faites-le tourner.

Oublier que la rotation est globale. Changer le secret invalide instantanément tous les liens en circulation, y compris ceux dans des emails envoyés il y a cinq minutes. C'est exactement ce que vous voulez pendant un incident et exactement ce que vous ne voulez pas un vendredi après-midi par accident.

FAQ URLs signées

Quelle est la différence entre une URL signée et une URL pré-signée ?

Principalement l'endroit où se fait la vérification. « URL pré-signée » est le terme S3 pour un lien temporaire émis par le service de stockage et vérifié par lui. Une URL signée en périphérie CDN est vérifiée en périphérie, près du visiteur, et fonctionne pour n'importe quelle origine plutôt que pour un simple bucket. Le concept est le même : une signature plus une expiration dans la chaîne de requête.

Quelqu'un peut-il partager un lien signé ?

Oui, jusqu'à son expiration. Une signature prouve que le lien a été émis par vous ; elle ne dit rien sur qui le détient. Des expirations courtes limitent les dégâts. Si vous avez besoin que le lien soit lié à une seule personne, incluez un élément identifiant dans le chemin signé et vérifiez-le de votre côté, et acceptez qu'un partageur déterminé puisse toujours transférer le fichier téléchargé.

La signature nuit-elle à la mise en cache ?

Seulement si vous laissez la signature entrer dans la clé de cache, et alors cela fait très mal — chaque lien unique devient sa propre entrée de cache et chaque téléchargement va vers votre origine. Configurez le mode de chaîne de requête pour ignorer les paramètres de signature, et le fichier se met en cache normalement, partagé entre tous ceux qui détiennent un lien valide.

Puis-je révoquer un seul lien ?

Pas individuellement. Une signature est valide jusqu'à son expiration, car la vérification est sans état — il n'y a aucune liste dont la retirer. Les contrôles disponibles sont une expiration courte et la rotation du secret, qui invalide tout d'un coup.

Le MD5 n'est-il pas cassé pour cet usage ?

Le MD5 est cassé pour la résistance aux collisions, ce qui compte quand un attaquant peut choisir les deux messages. Ici, l'attaquant doit forger un hash d'une chaîne contenant un secret qu'il ne possède pas, ce qui est un problème de préimage plutôt que de collision. Le risque pratique, c'est que le secret fuite ou soit devinable — utilisez-en un long et aléatoire, gardez-le côté serveur, et faites-le tourner.

Devrais-je utiliser cela pour de la vidéo HLS ?

Cela fonctionne, avec la réserve sur la durée de session : l'expiration doit couvrir toute la lecture, pas seulement la requête du manifeste, sinon la lecture s'arrête en cours de route. Pour du contenu long, associez une expiration généreuse à du rate limiting plutôt qu'une expiration très courte qui casse le lecteur.