Recherche Publié le · 8 min de lecture

Nous avons audité notre propre site comme celui d'un client

Quatre constats sur cyberaar.io, dont TLS 1.0 encore accepté en bordure et un playbook qui annonçait un succès sans avoir rien fait. Commandes incluses.

Le site d’un prestataire de sécurité est la première chose qu’un prospect teste. Pas son offre : son en-tête HTTP. C’est gratuit, c’est anonyme, et cela répond à une question que personne ne pose en réunion : est-ce que ces gens appliquent chez eux ce qu’ils vont nous facturer ?

Nous avons donc passé cyberaar.io au même jeu de vérifications que celui d’un client. Voici ce que nous y avons trouvé, y compris ce qui n’allait pas.

Constat 1 : aucun enregistrement CAA, et un piège dans le correctif

Un enregistrement CAA (Certification Authority Authorization) déclare, dans le DNS, quelles autorités de certification ont le droit d’émettre un certificat pour votre domaine. En son absence, la réponse par défaut est : toutes. Le domaine n’avait aucun CAA. Ce n’est pas une vulnérabilité exploitable en soi, c’est une contrainte manquante : rien dans le DNS n’empêchait une AC quelconque d’émettre un certificat valide pour cyberaar.io.

Le correctif paraît évident. Nous utilisons Let’s Encrypt, donc on autorise Let’s Encrypt et on ferme le reste :

cyberaar.io. IN CAA 0 issue "letsencrypt.org"

C’est exactement ce qu’il ne faut pas faire derrière Cloudflare, et c’est le constat qui justifie cet article.

Le certificat que voit un visiteur n’est pas le nôtre : c’est celui que Cloudflare présente en bordure, via Universal SSL. Or Cloudflare n’émet pas ce certificat toujours auprès de la même autorité. Le service tourne sur plusieurs AC, et l’autorité retenue peut changer d’un renouvellement à l’autre. Un CAA restreint à letsencrypt.org fonctionne donc parfaitement le jour où on le pose, puis casse le renouvellement en bordure au moment où Cloudflare bascule sur une autre autorité.

La panne serait différée de plusieurs semaines par rapport au changement qui l’a causée, et se manifesterait par une erreur de certificat côté visiteur, sans aucune modification récente à incriminer. C’est le pire profil de panne qui existe.

L’ensemble effectivement autorisé couvre donc les autorités mobilisées par le service, letsencrypt.org, pki.goog, ssl.com et sectigo.com, plus une adresse iodef pour être prévenus d’une demande d’émission refusée.

Deux précisions qui évitent une fausse alerte au contrôle suivant :

  • Une fois qu’un CAA existe sur la zone, Cloudflare complète automatiquement l’ensemble avec les autorités dont il a besoin. La zone finit par afficher une douzaine d’enregistrements là où cinq ont été déclarés. C’est le comportement attendu, pas une dérive de configuration.
  • Tant que le DNS reste chez Cloudflare, ce que la liste déclarée garantit réellement se limite à l’adresse iodef et à la justesse de l’ensemble le jour où le DNS partira ailleurs. Il faut savoir ce qu’on achète avec ce contrôle : ce n’est pas un verrou, c’est une contrainte déclarative et une alerte.

Constat 2 : security.txt avait deux sources de vérité

Le fichier /.well-known/security.txt (RFC 9116) indique comment signaler une vulnérabilité. Il porte un champ Expires obligatoire : passée cette date, le fichier n’est plus conforme et un chercheur est fondé à considérer que le canal n’est plus maintenu.

Le nôtre existait en deux exemplaires : un fichier statique dans les sources du site, et un modèle généré au déploiement avec une date d’expiration calculée. Les deux se déployaient. Le second était écrasé par le premier, parce que la synchronisation des fichiers statiques s’exécutait après la génération du modèle et supprimait ce qui ne lui appartenait pas.

Conséquences concrètes : la ligne Policy n’atteignait jamais la production, et la date d’expiration était figée en dur au lieu d’être recalculée. Le fichier allait donc devenir silencieusement non conforme, à une date connue d’avance, sans que rien ne le signale.

La copie statique a été supprimée et la génération du modèle passe désormais après la synchronisation. La règle qui en découle est générale : un fichier qui doit expirer ne peut pas être un actif statique. S’il porte une date, il doit être produit par ce qui le déploie.

Constat 3 : le playbook annonçait un succès sans rien faire

Celui-ci n’est pas un défaut du site, c’est un défaut de la méthode, et c’est probablement le plus utile des trois.

Les tâches qui posent les enregistrements CAA ont besoin d’une valeur produite par une tâche antérieure, qui identifie la zone DNS. Ces deux tâches ne portaient pas les mêmes étiquettes d’exécution. En lançant le déploiement restreint aux tâches DNS, la tâche d’identification de zone était donc ignorée, et toutes les tâches CAA qui en dépendaient ne faisaient rien.

Le déploiement s’est terminé en annonçant un succès. La tâche finale de compte rendu s’exécutait normalement et affichait le résultat attendu. Rien, dans la sortie de l’outil, ne distinguait ce déploiement d’un déploiement réussi.

L’écart n’a été détecté qu’en interrogeant un résolveur DNS externe, qui ne renvoyait aucun CAA. D’où la règle que nous appliquons depuis : une modification DNS ou TLS se vérifie contre un résolveur externe, jamais contre l’outil qui l’a produite. Un outil de déploiement rapporte ce qu’il a tenté, pas ce que le monde observe.

Constat 4 : celui que la rédaction de cet article a produit

La section finale de cet article propose quatre commandes de vérification. Nous les avons exécutées sur notre propre domaine pour nous assurer qu’elles étaient justes. La dernière a répondu autre chose que ce que nos notes affirmaient.

Nos notes internes portaient la mention « TLS 1.3 uniquement, TLS 1.0 et 1.1 refusés », rangée parmi les points vérifiés et clos. La réalité, mesurée depuis l’extérieur :

Protocol  : TLSv1
Cipher    : ECDHE-ECDSA-AES128-SHA

Négociation complète en TLS 1.0. Pas un avertissement de configuration : une poignée de main aboutie, sur le domaine d’une entreprise de sécurité.

Pourquoi la note était fausse est la partie intéressante. Le test d’origine avait selon toute vraisemblance été écrit ainsi :

openssl s_client -connect cyberaar.io:443 -tls1_1

Sur OpenSSL 3.x, cette commande échoue avec no protocols available quelle que soit la configuration du serveur : les versions obsolètes sont désactivées côté client. L’échec ressemble trait pour trait à un refus du serveur. Quelqu’un a lancé la commande, vu un échec, conclu que TLS 1.1 était refusé, et classé le point. C’est exactement le constat 3 sous une autre forme : on avait vérifié l’outil, pas le monde.

La cause technique mérite d’être connue au-delà de notre cas. Derrière un CDN, la version minimale de TLS est un réglage de bordure. C’est Cloudflare qui termine la connexion du visiteur, pas notre reverse proxy. Le durcissement TLS appliqué à l’origine n’a donc aucun effet sur ce que le visiteur peut négocier, et la valeur par défaut de ce réglage en bordure est TLS 1.0. Beaucoup d’équipes durcissent soigneusement l’origine et laissent la bordure à sa valeur d’usine : la surface réellement exposée est la seconde.

Correction appliquée le 20 août 2026, version minimale portée à TLS 1.2 dans SSL/TLS > Edge Certificates > Minimum TLS Version.

Deux leçons, dont une qui nous coûte quelque chose à écrire :

  • Une mention « vérifié » a une date de péremption, et la nôtre était en plus fausse dès l’origine. Un registre de contrôles n’est pas une preuve, c’est un souvenir.
  • Vérifiez la bordure, pas l’origine. Le visiteur ne parle jamais à votre serveur.

Ce qui était déjà en état

Un audit honnête publie aussi ce qui passe, sinon il ne mesure rien. Vérifié depuis l’extérieur :

  • Aucun cookie. Le site n’en dépose aucun, ce qui explique l’absence de bandeau de consentement. Ce n’est pas un oubli, c’est la conséquence de ne pas avoir de mesure d’audience tierce.
  • HTTP/3 disponible. TLS 1.3 négocié par défaut, TLS 1.2 en plancher depuis le constat 4.
  • Aucune exposition de .git, de .env ni de fichiers de correspondance de sources. Pas de listage de répertoire.
  • TRACE, TRACK, PUT et DELETE répondent 405.
  • Aucun en-tête CORS permissif sur l’API.
  • La politique de sécurité de contenu a été resserrée à cette occasion, avec object-src 'none' et upgrade-insecure-requests.

HSTS preload : un engagement, pas une case à cocher

Le domaine a été soumis à la liste de préchargement HSTS. Cela signifie que les navigateurs refuseront toute connexion non chiffrée vers cyberaar.io et ses sous-domaines, sans même tenter la requête.

C’est une décision à prendre en connaissance de cause, parce qu’elle est difficilement réversible : une sortie de liste se compte en mois, et non en minutes. Concrètement, tout sous-domaine destiné à un navigateur doit servir du HTTPS, définitivement. Dans notre cas la contrainte ne coûte rien, tout étant déjà derrière un reverse proxy avec certificats automatiques. Elle mérite d’être évaluée avant, pas après. À noter que le préchargement HSTS ne concerne que les navigateurs : les agents et les appels d’API ne sont pas affectés.

Vérifiez le vôtre

Rien de ce qui précède n’exige d’outil particulier. Ces quatre commandes répondent à l’essentiel, sur votre domaine comme sur le nôtre :

# Quelles AC peuvent émettre pour votre domaine ? (vide = toutes)
dig CAA exemple.com +short

# HSTS annoncé, et avec quelle durée ?
curl -sI https://exemple.com | grep -i strict-transport-security

# Le canal de signalement existe-t-il, et a-t-il expiré ?
curl -s https://exemple.com/.well-known/security.txt

# Quelle version de TLS est réellement négociée ?
openssl s_client -connect exemple.com:443 -servername exemple.com </dev/null 2>/dev/null \
  | grep -E "Protocol|Cipher"

Pour tester si une version obsolète est encore acceptée, il faut abaisser le niveau de sécurité du client, sans quoi vous mesurez votre poste de travail et non le serveur, comme au constat 4 :

openssl s_client -connect exemple.com:443 -servername exemple.com \
  -tls1 -cipher 'DEFAULT@SECLEVEL=0' </dev/null 2>&1 | grep -E "New,|Protocol"

Si la réponse contient TLSv1, le serveur accepte encore TLS 1.0. Derrière un CDN, le réglage à corriger est celui de la bordure, pas celui de votre serveur.

Si la première commande ne renvoie rien, commencez par là, et lisez le constat 1 avant de poser la ligne évidente.

Nous publions ces éléments parce que notre argument commercial est que nos clients peuvent inspecter ce que nous opérons. Cela commence par nos propres domaines. Une erreur, une objection, un désaccord technique : [email protected].

tlscaacloudflaresecurity-txtansible