// Engineering Log
HTTP, HTTPS и TLS: Часть 10 — Отладка TLS: curl, openssl s_client и разбор ошибок сертификатов
Опубликовано 16.10.2026
// Быстрый маршрут
Эта статья относится к теме Безопасность и защита.
Большинство проблем с HTTPS сводится к нескольким причинам: неполная цепочка сертификатов, просроченный сертификат, неверное имя в сертификате, несовпадение версий или шифров, вмешательство промежуточного оборудования. Браузер обычно показывает общее «Подключение не защищено», а точную причину дают два инструмента: curl и openssl s_client. В этой части — как ими пользоваться и как читать их вывод.
Что показывает curl -v
curl -sv -o /dev/null https://example.ru/ 2>&1 | grep '^\*'* Host example.ru:443 was resolved.
* Trying 192.0.2.10:443...
* Connected to example.ru (192.0.2.10) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519 / RSASSA-PSS
* ALPN: server accepted h2
* Server certificate:
* subject: CN=example.ru
* start date: Sep 1 00:00:00 2026 GMT
* expire date: Nov 30 23:59:59 2026 GMT
* subjectAltName: host "example.ru" matched cert's "example.ru"
* issuer: C=US; O=Let's Encrypt; CN=R11
* SSL certificate verify ok.Из вывода видно: к какому IP подключились, какая версия TLS и шифр согласованы, какой протокол выбран через ALPN, кому и кем выдан сертификат, до какого числа он действует и совпало ли имя. Формат вывода немного отличается в зависимости от TLS-библиотеки, с которой собран curl (OpenSSL, LibreSSL, GnuTLS, Schannel в Windows): curl --version показывает её в первой строке.
Ключи curl для TLS
curl --tlsv1.2 --tls-max 1.2 https://example.ru/ # только TLS 1.2
curl --tlsv1.3 https://example.ru/ # не ниже TLS 1.3
curl --ciphers ECDHE-RSA-AES128-GCM-SHA256 --tls-max 1.2 https://example.ru/ # конкретный шифр TLS 1.2
curl --cacert internal-ca.crt https://intranet.example.ru/ # доверять своему CA
curl --cert client.crt --key client.key https://admin.example.ru/ # клиентский сертификат (mTLS)
curl -k https://example.ru/ # не проверять сертификат — только для диагностикиКлюч --tlsv1.2 означает «не ниже 1.2», а не «ровно 1.2». Чтобы проверить, поддерживает ли сервер именно 1.2, нужен ещё --tls-max 1.2.
-k (--insecure) полезен, чтобы отделить проблему сертификата от остальных: если с -k всё работает, дело в сертификате. Оставлять -k в скриптах нельзя.
openssl s_client
s_client — TLS-клиент из OpenSSL, который выполняет рукопожатие и показывает всё, что прислал сервер.
openssl s_client -connect example.ru:443 -servername example.ru </dev/null-servernameзадаёт SNI. В OpenSSL 1.1.1 и новее SNI берётся из-connectавтоматически, если там имя, а не IP. Если вы подключаетесь по IP, указывайте-servernameявно, иначе получите сертификат по умолчанию;</dev/nullзакрывает ввод, чтобы команда завершилась сразу после рукопожатия.
Главное в выводе:
Certificate chain
0 s:CN=example.ru
i:C=US, O=Let's Encrypt, CN=R11
1 s:C=US, O=Let's Encrypt, CN=R11
i:C=US, O=Internet Security Research Group, CN=ISRG Root X1
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
...
Verify return code: 0 (ok)- Certificate chain — что прислал сервер:
s— кому выдан,i— кем. У каждого следующегоsдолжен совпадать сiпредыдущего. Если в цепочке только строка0, сервер не отдаёт промежуточный сертификат; - Verify return code: 0 (ok) — цепочка проверена. Любое другое значение — ошибка с пояснением.
Краткий вывод и частные случаи:
openssl s_client -connect example.ru:443 -brief </dev/null # только версия, шифр, проверка
openssl s_client -connect example.ru:443 -showcerts </dev/null # все сертификаты цепочки в PEM
openssl s_client -connect example.ru:443 -tls1_2 </dev/null # только TLS 1.2
openssl s_client -connect example.ru:443 -alpn h2 </dev/null # проверить ALPN
openssl s_client -connect example.ru:443 -status </dev/null # ответ OCSP, если сервер его прикладывает
openssl s_client -connect mail.example.ru:587 -starttls smtp </dev/null # TLS в почтовых протоколах-starttls работает для smtp, imap, pop3, ftp, xmpp, postgres, mysql и других протоколов, где TLS включается командой внутри открытого соединения.
Сведения о сертификате
Срок действия, имена и издатель сертификата на сервере:
openssl s_client -connect example.ru:443 -servername example.ru </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltNamesubject=CN=example.ru
issuer=C=US, O=Let's Encrypt, CN=R11
notBefore=Sep 1 00:00:00 2026 GMT
notAfter=Nov 30 23:59:59 2026 GMT
X509v3 Subject Alternative Name:
DNS:example.ru, DNS:www.example.ruКлюч -ext есть в OpenSSL 1.1.1 и новее. Для файла сертификата на диске — openssl x509 -in cert.pem -noout -text.
Проверить, истечёт ли сертификат в ближайшие 14 дней (код возврата 1 — истечёт):
openssl s_client -connect example.ru:443 -servername example.ru </dev/null 2>/dev/null \
| openssl x509 -noout -checkend $((14*24*3600)) && echo ok || echo 'истекает'Для постоянного контроля лучше мониторинг: Prometheus blackbox_exporter отдаёт метрику probe_ssl_earliest_cert_expiry — дату истечения самого раннего сертификата в цепочке, и по ней настраивается оповещение.
Проверить, что ключ соответствует сертификату (хеши должны совпасть):
openssl x509 -in cert.pem -noout -pubkey | openssl sha256
openssl pkey -in privkey.pem -pubout | openssl sha256Проверить цепочку из файлов:
openssl verify -untrusted chain.pem cert.pemКакие версии и шифры поддерживает сервер
Вручную — перебором -tls1, -tls1_1, -tls1_2, -tls1_3 в s_client. Удобнее готовые инструменты:
nmap --script ssl-enum-ciphers -p 443 example.ru
testssl.sh example.rutestssl.sh проверяет версии, шифры, цепочку, HSTS, известные уязвимости и работает без установки, из одного скрипта. Для публичных сайтов то же делает SSL Labs.
Расшифровать трафик в Wireshark
Как записывать трафик через tcpdump и работать с Wireshark, описано в статье «Сетевой траблшутинг: tcpdump, sngrep и Wireshark».
Иногда нужно увидеть сам HTTP внутри TLS: что именно отправляет приложение, какие заголовки уходят. Для этого клиент записывает ключи сессий в файл, а Wireshark ими расшифровывает трафик.
export SSLKEYLOGFILE=$HOME/tls-keys.log
curl https://example.ru/ # curl, собранный с OpenSSL, BoringSSL или GnuTLS
# или запустите Chrome/Firefox из этой же оболочкиВ Wireshark: Настройки → Protocols → TLS → (Pre)-Master-Secret log filename — укажите файл. Трафик, записанный в это время, покажется расшифрованным, включая HTTP/2.
Файл ключей позволяет расшифровать всю записанную переписку — храните его как пароль и удаляйте после отладки. Системный curl в macOS собран с LibreSSL и может не поддерживать SSLKEYLOGFILE; используйте curl из Homebrew.
Частые ошибки и что они значат
unable to get local issuer certificate (curl, код 60; в s_client — verify error:num=20). Клиент не может построить цепочку до доверенного корня. Причины:
- сервер не отдаёт промежуточный сертификат — исправьте на сервере:
fullchain.pemвместоcert.pem; - сертификат выпущен внутренним CA, которого нет у клиента —
--cacertили установка корня в систему; - в системе устаревшее хранилище корневых сертификатов — обновите пакет
ca-certificates.
certificate has expired (код 10). Проверьте даты. Если сертификат на сервере свежий, а клиент видит старый — веб-сервер не перечитал сертификат после продления (nginx -s reload) или ответ идёт с другого узла балансировщика.
no alternative certificate subject name matches target host name (curl, код 60). Имени нет в SAN. Частые причины: заход на www. при сертификате только на домен; подключение без SNI или по IP; сертификат по умолчанию от другого сайта на этом сервере.
self-signed certificate / self-signed certificate in certificate chain (коды 18 и 19). Самоподписанный сертификат, или цепочка заканчивается корнем, которому клиент не доверяет. Если в издателе стоит имя антивируса или корпоративного шлюза, трафик расшифровывается по пути.
tlsv1 alert protocol version, unsupported protocol (curl, код 35). Нет общей версии TLS: старый клиент (только TLS 1.0) и современный сервер, или наоборот. Проверьте --tlsv1.2 --tls-max 1.2 и -tls1_2 в s_client.
sslv3 alert handshake failure (код 35). Нет общего шифра или группы, либо сервер требует клиентский сертификат. В выводе s_client с -state видно, на каком шаге рукопожатие оборвалось.
Connection reset by peer сразу после ClientHello. Сервер или оборудование по пути сбросило соединение, увидев ClientHello. Если по IP (без SNI) соединение проходит, а с именем — нет, это признак фильтрации по SNI на пути. Бывает и на корпоративных межсетевых экранах, которые не пропускают большой ClientHello с постквантовой группой X25519MLKEM768: проверьте с -groups x25519 в s_client или --curves x25519 в curl.
SSL routines::wrong version number в s_client. Вы подключились по TLS к порту, где TLS нет: например, к порту 80, или к 587, где нужен -starttls smtp, или сервер на 443 отвечает обычным HTTP.
Браузер открывает, а curl или приложение — нет. Почти всегда неполная цепочка: браузеры достраивают промежуточные сертификаты сами, библиотеки — нет. Проверка: openssl s_client -showcerts и строка Certificate chain.
Порядок диагностики
curl -sv -o /dev/null https://имя/— доходит ли до TLS, на каком шаге ошибка, код ошибки curl.openssl s_client -connect имя:443 -servername имя— цепочка иVerify return code.openssl x509 -noout -dates -ext subjectAltName— сроки и имена.curl --resolve имя:443:IP— ведут ли себя одинаково все серверы за балансировщиком.testssl.sh имя— версии, шифры и полная проверка настроек.- Если ничего не помогло — запись трафика и Wireshark с
SSLKEYLOGFILE.
// Похожая задача
Если у вас похожая ситуация
Эта статья относится к одной из рабочих тем. Можно продолжить чтение по теме, перейти на главную, чтобы понять, чем я занимаюсь, или сразу открыть услуги.
Тема статьи
Безопасность и защита
SSL, hardening, доступы, защита сервисов и безопасные конфигурации.
Часто с этим приходят
- Настроить SSL, сертификаты и безопасные подключения
- Ограничить доступы и закрыть лишние точки входа
- Усилить конфигурацию сервера и сервисов
// Следующий шаг
Если вам нужна не только статья, а помощь по этой теме, удобнее сразу перейти в услугу. Главная и подборка материалов остаются рядом.
Открыть услуги// Contact
Нужна помощь?
Свяжись со мной и я помогу решить проблему
Написать в TelegramОтвечаю в течение рабочего дня (03:00–13:00 GMT)
Или оставьте заявку здесь:
// Related