web-dev-qa-db-fra.com

curl: comment spécifier le nom d'hôte cible pour la demande https

J'ai un x.example Qui dessert le trafic à la fois a.example Et b.example. x.example Possède des certificats pour a.example Et b.example. Le DNS pour a.example Et b.example N'est pas encore configuré.

Si j'ajoute une entrée /etc/hosts Pour a.example Pointant vers l'ip de x.example Et que je lance curl -XGET https://a.example, J'obtiens un 200.

Cependant, si je lance curl --header 'Host: a.example' https://x.example, J'obtiens:

curl: (51) SSL: aucun autre nom de sujet de certificat ne correspond au nom d'hôte cible x.example

Je pense qu'il utiliserait a.example comme hôte. Peut-être que je ne comprends pas comment fonctionne SNI/TLS.

Parce que a.example Est un en-tête HTTP, la prise de contact TLS n'y a pas encore accès? Mais l'URL à laquelle elle a accès?

7
lf215

En effet SNI dans TLS ne fonctionne pas comme ça. SNI, comme tout ce qui concerne TLS, se produit avant tout type de trafic HTTP, donc l'en-tête Host n'est pas pris en compte à cette étape (mais sera utile plus tard pour que le serveur web sache quel hôte vous connectez aussi).

Donc, pour activer SNI, vous avez besoin d'un commutateur spécifique dans votre client HTTP pour lui dire d'envoyer l'extension TLS appropriée pendant la négociation avec la valeur de nom d'hôte dont vous avez besoin.

Dans le cas de curl, vous avez besoin d'au moins la version 7.18.1 (basée sur https://curl.haxx.se/changes.html ), puis il semble utiliser automatiquement le valeur fournie dans l'en-tête Host. Cela dépend également de la version d'OpenSSL (ou de la bibliothèque équivalente sur votre plateforme) à laquelle il est lié.

Voir le point 1.10 de https://curl.haxx.se/docs/knownbugs.html qui parle d'un bogue mais explique ce qui se passe:

Lorsqu'une URL avec un point de fin pour la partie Nom d'hôte: " https://example.com./ ", libcurl supprime le point et utilise le nom sans point en interne et l'envoie sans point dans HTTP Host: en-têtes et dans le champ TLS SNI.

L'option --connect-to Pourrait également être utile dans votre cas. Ou --resolve En remplacement de /etc/hosts, Voir https://curl.haxx.se/mail/archive-2015-01/0042.html pour un exemple par exemple , ou https://makandracards.com/makandra/1613-make-an-http-request-to-a-machine-but-fake-the-hostname Vous pouvez ajouter --verbose dans tous les cas pour voir plus en détail ce qui se passe. Voir cet exemple: https://www.claudiokuenzler.com/blog/693/curious-case-of-curl-ssl-tls-sni-http-Host-header ; vous y verrez également comment tester directement avec openssl.

Si vous avez a.example Dans votre /etc/hosts, Vous devez simplement exécuter curl avec https://a.example/ Et il doit prendre en charge l'en-tête Host et donc SNI (ou utiliser --resolve À la place)

10
Patrick Mevzek

La réponse sélectionnée m'a aidé à trouver la réponse, même si elle ne contient pas la réponse. La réponse dans le lien mail/archive fourni par Patrick Mevzek a le mauvais numéro de port . Donc, même en suivant cette réponse, elle continuera à échouer.

J'ai utilisé ce conteneur pour exécuter un serveur de débogage pour inspecter les demandes. Je suggère fortement à quiconque débogue ce type de problème de faire de même.

Voici comment répondre à la question du PO.

# Instead of this:
# curl --header 'Host: a.example'        https://x.example

# Do:
  Host=a.example
  target=x.example

  ip=$(Dig +short x.example | head -n1)
  curl -sv   --resolve $Host:443:$ip https://$Host

Remarque : Puisque vous utilisez https, vous devez utiliser 443 dans le --resolve argument au lieu de 80 comme indiqué sur le mail/archive

4
Bruno Bronosky