HTTPS отдаёт сертификат чужого сайта — диагностируйте SNI-несоответствие
Пользователи shop.example.com ловят ошибку несоответствия сертификата, но только часть клиентов. На этом одном IP живёт много HTTPS-сайтов. Вы пробуете с SNI и без. Объясните, почему части клиентов отдаётся не тот сертификат, и дайте фикс.
# Проба БЕЗ SNI (голый IP, без -servername) — старый клиент / health-check:
$ openssl s_client -connect 203.0.113.10:443 </dev/null 2>/dev/null \
| openssl x509 -noout -subject
subject=CN=default.example.com # отдан НЕ ТОТ серт
# Проба С SNI:
$ openssl s_client -connect 203.0.113.10:443 -servername shop.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject
subject=CN=shop.example.com # верный серт присутствует
$ curl -v https://shop.example.com/
* SSL: no alternative certificate subject name matches target host name 'shop.example.com'
Определите причину и дайте фикс.
Много HTTPS-сайтов делят один IP и порт, поэтому сервер выбирает сертификат по полю SNI (имя хоста в client hello). Запрос без SNI (старый клиент, голый IP) получает серт хоста по умолчанию — отсюда несоответствие у таких клиентов. Фикс: слать SNI и сделать нужный сайт default server-блоком.
- ✗Винить DNS или истёкший серт вместо выбора по SNI
- ✗Считать, что один IP навязывает единый общий сертификат всем сайтам
- ✗Забывать, что клиенты без SNI падают на хост по умолчанию
- →Почему голый IP или очень старый клиент вызывает это, а браузеры нет?
- →Как server-блок по умолчанию меняет запасной сертификат?
Решение
1. Почему части клиентов приходит не тот серт
На одном IP:443 живёт много сайтов, поэтому веб-сервер решает, какой сертификат отдать, по полю SNI (имя хоста в TLS client hello). Проба показывает вилку:
без -servername → CN=default.example.com (не тот серт)
с -servername → CN=shop.example.com (верный серт присутствует)
Значит, конфигурация в порядке — верный серт есть. Проблема в том, что часть клиентов не шлёт SNI (соединение по голому IP, очень старый клиент, health-check), и им отдаётся сертификат виртуального хоста по умолчанию — default.example.com. Отсюда subjectAltName does NOT match.
2. Фикс
даже запрос без SNI получал вменяемый серт, а не чужой.
- Убедиться, что клиент шлёт SNI (обращаться по имени хоста, обновить старые клиенты).
- Назначить
shop.example.comдефолтным server-блоком (default_server), чтобы - Либо выдать проблемным путям отдельный listener/сертификат.
SNI виден до шифрования (в открытом client hello), поэтому выбор серта по нему возможен.