curl: как указать целевое имя хоста для запроса https
У меня есть x.example
который обслуживает трафик для обоих a.example
а также b.example
,x.example
имеет сертификаты для обоих a.example
а также b.example
, DNS для a.example
а также b.example
еще не настроен.
Если я добавлю /etc/hosts
запись для a.example
указывая на x.example
айпи и беги curl -XGET https://a.example
Я получаю 200.
Однако, если я бегу curl --header 'Host: a.example' https://x.example
, Я получил:
curl: (51) SSL: альтернативное имя субъекта сертификата не соответствует имени целевого хоста x.example
Я думаю, он будет использовать.example в качестве хоста. Может быть, я не понимаю, как работает SNI/TLS.
Так как a.example
заголовок HTTP, к которому у TLS-рукопожатия еще нет доступа? Но сам URL, к которому он имеет доступ?
3 ответа
На самом деле SNI в TLS не работает так. SNI, как и все, что связано с TLS, происходит перед любым видом трафика HTTP, поэтому Host
заголовок не учитывается на этом этапе (но позже будет полезно, чтобы веб-сервер знал, к какому хосту вы подключаетесь).
Таким образом, чтобы включить SNI, вам нужен определенный переключатель в вашем HTTP-клиенте, чтобы он отправлял соответствующее расширение TLS во время квитирования с нужным вам значением имени хоста.
В случае curl
вам нужна как минимум версия 7.18.1 (на основе https://curl.haxx.se/changes.html), а затем она автоматически использует значение, указанное в Host
заголовок. Это зависит от того, с какой версией OpenSSL (или эквивалентной библиотеки на вашей платформе) он связан.
Смотрите пункт 1.10 в https://curl.haxx.se/docs/knownbugs.html котором говорится об ошибке, но объясняется, что происходит:
Получив URL-адрес с конечной точкой для части имени хоста: " https://example.com/", libcurl удалит точку и будет использовать имя без точки внутри и отправит его без точки в HTTP-хосте: Заголовки и в поле TLS SNI.
--connect-to
опция также может быть полезна в вашем случае. Или же --resolve
в качестве замены /etc/hosts
см. https://curl.haxx.se/mail/archive-2015-01/0042.html для примера или https://makandracards.com/makandra/1613-make-an-http-request-to-a-machine-but-fake-the-hostname Вы можете добавить --verbose
во всех случаях, чтобы увидеть более подробно, что происходит. Смотрите этот пример: https://www.claudiokuenzler.com/blog/693/curious-case-of-curl-ssl-tls-sni-http-host-header; вы также увидите там, как тестировать напрямую с openssl
,
Если у вас есть a.example
в вашем /etc/hosts
Вы должны просто запустить curl с https://a.example/
и это должно заботиться о Host
заголовок и, следовательно, SNI (или использовать --resolve
вместо)
Выбранный ответ помог мне найти ответ, хотя он и не содержит ответа. Ответ в ссылке на почту / архив, предоставленную Патриком Мевзеком, имеет неправильный номер порта. Так что даже следование этому ответу приведет к продолжению сбоя.
Я использовал этот контейнер для запуска сервера отладки для проверки запросов. Я настоятельно рекомендую всем, кто занимается отладкой такого рода проблем, сделать то же самое.
Вот как ответить на вопрос ОП.
# 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
Примечание. Поскольку вы используете https, вы должны использовать443
в --resolve
аргумент вместо 80
как было написано на почте / в архиве
У меня была похожая потребность. Не было доступа sudo для обновления файла hosts.
Я использую параметр разрешения , а также добавляю имя хоста DNS в качестве параметра заголовка .
--resolve <dns name>:<port>:<ip addr>
curl --request POST --resolve dns_name:443:a.b.c.d 'https://dns_name/x/y' --header 'Host: dns_name' ....
Ваше здоровье..