curl: как указать целевое имя хоста для запроса https

У меня есть x.example, который обслуживает трафик как для a.example, так и для b.example. x.example имеет сертификаты как для a.example, так и для b.example. DNS для a.example и b.example еще не настроен.

Если я добавлю запись /etc/hosts для a.example, указывающую на IP-адрес x.example, и запущу curl -XGET https://a.example, я получу 200.

Однако, если я запускаю curl --header 'Host: a.example' https://x.example, я получаю:

curl: (51) SSL: альтернативное имя субъекта сертификата не соответствует целевому имени хоста x.example

Я думаю, что он будет использовать a.example в качестве хоста. Возможно, я не понимаю, как работает SNI/TLS.

Поскольку a.example является заголовком HTTP, рукопожатие TLS еще не имеет к нему доступа? Но сам URL-адрес, к которому у него есть доступ?


person lf215    schedule 10.05.2018    source источник


Ответы (2)


Ведь 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 Host: и в поле 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)

Итак, чтобы ответить на ваш вопрос напрямую, замените

curl --header 'Host: a.example' https://x.example

с

curl --connect-to a.example:443:x.example:443 https://a.example

и он должен работать идеально.

person Patrick Mevzek    schedule 10.05.2018

Выбранный ответ помог мне найти ответ, хотя он не содержит ответа. Ответ в почтовой/архивной ссылке, предоставленной Патриком Мевзеком, имеет неправильный номер порта. Поэтому даже следование этому ответу приведет к тому, что он продолжит терпеть неудачу.

Я использовал этот контейнер для запуска сервера отладки для проверки запросов. Я настоятельно рекомендую всем, кто отлаживает подобные проблемы, сделать то же самое.

Вот как ответить на вопрос ОП.

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

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

  ip=$(dig +short $target | head -n1)
  curl -sv   --resolve $host:443:$ip https://$host

Если вы хотите игнорировать неверные совпадения сертификатов, используйте -svk вместо -sv

curl -svk --resolve $host:443:$ip https://$host

Примечание. Поскольку вы используете https, вы должны использовать 443 в аргументе --resolve вместо 80, как указано в почта/архив

person Bruno Bronosky    schedule 09.09.2019
comment
Очень полезно на Mac, так как Catalina больше не позволяет вам вручную настраивать файл hosts. - person Sam Critchley; 04.02.2020
comment
вместо этого `ip=$(dig +short x.example | head -n1)` используйте `ip=$(dig +short $target | head -n1)` - person Rax; 02.11.2020
comment
Дох! Исправлено. Спасибо, @Rax. (Я скучаю по вашим бутербродам с ростбифом. У Арби хуже.) - person Bruno Bronosky; 03.12.2020