Проверка TLS своего сайта: openssl s_client и curl вместо онлайн-сканеров

Онлайн-проверки TLS удобны, но они проверяют сайт снаружи, показывают не всё и не годятся для внутренних сервисов. Три команды, openssl s_client, openssl x509 и curl, отвечают на основные вопросы за минуту: действует ли сертификат и кому он выдан, какие версии протокола принимает сервер, полная ли цепочка и перенаправляется ли HTTP на HTTPS. Ниже набор проверок с ожидаемыми результатами; примеры выводов получены на настоящем сервере и показаны с заменой имён на example.com.
Статья опирается на логику направления «Сетевая безопасность» из методики зрелости Группы Сбер (источник); это методика для крупных компаний, мы используем её как ориентир и пересказываем своими словами. Проверяйте только свои сервисы или с разрешения владельца. Версия OpenSSL влияет на формат вывода: примеры получены на OpenSSL 3.0.
Что должно получиться
| Уровень | Что это значит на практике |
|---|---|
| 2. Гигиенический | Публичные сервисы защищены и контролируются, правила пересматриваются; сертификаты действуют и отслеживаются |
Критерии сформулированы нами по мотивам методики, это ориентир, а не оценка соответствия.
1. Сертификат: кому выдан и до какой даты
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject -issuer -dates -ext subjectAltName
Ключ -servername обязателен для серверов, которые держат несколько сайтов на одном адресе (SNI). Без него вы можете увидеть сертификат по умолчанию. Пример результата:
subject=CN = example.com
issuer=C = US, O = Let's Encrypt, CN = R10
notBefore=Oct 6 16:54:32 2026 GMT
notAfter=Jan 4 16:54:31 2027 GMT
X509v3 Subject Alternative Name:
DNS:example.com, DNS:*.example.com
Что смотреть: имя в subject и Subject Alternative Name должно покрывать проверяемое имя, notAfter — срок действия; запас менее 14 дней означает, что автоматическое продление не работает или вот-вот сломается. Срок до окончания можно проверить автоматически: openssl x509 -checkend 1209600 -noout вернёт код 0, если сертификат действует ещё минимум 14 дней (1209600 секунд). Готовый скрипт на несколько сайтов: Python и Bash для ИБ.
2. Цепочка и доверие
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | grep -E "^New,|Verify return code|Protocol|Cipher is"
New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256
Protocol : TLSv1.3
Verify return code: 0 (ok)
Что смотреть: Verify return code: 0 (ok) означает, что цепочка до доверенного корневого сертификата построена. Коды 20 и 21 («unable to get local issuer certificate», «unable to verify the first certificate») указывают, что сервер не отдаёт промежуточный сертификат: настройте полную цепочку (в nginx это fullchain.pem). Код 10 — сертификат просрочен, код 18 или 19 — самоподписанный. Для просмотра всех сертификатов цепочки добавьте опцию -showcerts.
3. Версии протокола
echo | openssl s_client -connect example.com:443 -servername example.com -tls1_3 2>/dev/null | grep -E "Protocol|Cipher is"
echo | openssl s_client -connect example.com:443 -servername example.com -tls1_2 2>/dev/null | grep -E "Protocol|Cipher is"
echo | openssl s_client -connect example.com:443 -servername example.com -tls1_1 2>&1 | grep -E "alert|error"
Ожидаемый результат для современного сервера:
Protocol : TLSv1.3
Cipher is TLS_AES_128_GCM_SHA256
Protocol : TLSv1.2
Cipher is ECDHE-RSA-AES256-GCM-SHA384
...error:0A00042E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version:...SSL alert number 70
Первая и вторая проверки показывают принятые версии и выбранные шифры, третья — отказ: сообщение tlsv1 alert protocol version означает, что сервер не поддерживает TLS 1.1, это правильно. Если TLS 1.1 или 1.0 принимается, отключите их в настройке сервера: безопасная настройка nginx. Если библиотека OpenSSL на вашей машине собрана без поддержки старых протоколов, результат отказа будет сообщением о локальной ошибке, а не ответом сервера: в таком случае проверьте другим инструментом.
Шифры, принимаемые в TLS 1.2, можно перебрать опцией -cipher; смысл — убедиться, что слабые наборы (RC4, 3DES, экспортные, без шифрования) недоступны. Для полного перебора используйте специализированные сканеры (например, testssl.sh или sslyze): они тоже запускаются локально и показывают полный отчёт.
4. HTTP, перенаправление и HSTS
curl -sI http://example.com/ | head -4
curl -sI https://example.com/ | grep -iE "^HTTP|strict-transport|^server"
HTTP/1.1 308 Permanent Redirect
Location: https://example.com/
HTTP/2 200
server: nginx
strict-transport-security: max-age=15552000
Что смотреть: HTTP перенаправляется на HTTPS кодом 301 или 308, на HTTPS присутствует HSTS, версия веб-сервера скрыта, протокол HTTP/2. Если HSTS нет, его стоит добавить после проверки работы всего сайта по HTTPS. Утечка версии в заголовке Server и заголовки X-Powered-By — повод поправить конфигурацию: убрать такие заголовки несложно, и это снижает информативность для сканеров.
5. Проверка конкретного ответа curl
curl -sv https://example.com/ -o /dev/null 2>&1 | grep -E "SSL connection|subject|expire date|issuer"
curl -s --tlsv1.2 --tls-max 1.2 -o /dev/null -w "%{http_code}\n" https://example.com/
curl -sI --resolve example.com:443:203.0.113.10 https://example.com/ | head -3
Первая команда показывает согласованный протокол, шифр и данные сертификата в выводе curl. Вторая принудительно ограничивает версию TLS: код 200 означает, что сервер принимает TLS 1.2. Третья проверяет конкретный сервер за балансировщиком или до смены DNS: --resolve подставляет нужный адрес для имени без изменения DNS.
6. Внутренние сервисы
Те же команды работают для служб на нестандартных портах: почта (-starttls smtp -connect mail.example.com:587), LDAP, базы данных с TLS. Для внутренних центров сертификации задайте корневой сертификат: openssl s_client -CAfile ca.pem -connect ..., иначе проверка покажет, что цепочка не доверена.
Типовые проблемы
| Симптом | Причина и что делать |
|---|---|
Браузер доверяет, а openssl — нет (код 20 или 21) |
Сервер не отдаёт промежуточный сертификат, браузер дозагружает его сам. Настройте полную цепочку на сервере |
| Сертификат не совпадает с именем | Нет SNI или не то имя в сертификате. Проверьте -servername и список имён в SAN |
| Сертификат продлили, а сервер показывает старый | Не перезагружен веб-сервер или несколько узлов за балансировщиком. Перезагрузите службу и проверьте каждый узел (--resolve) |
| TLS 1.1 принимается | Не отключены старые протоколы. Задайте ssl_protocols TLSv1.2 TLSv1.3 и перезагрузите |
| HTTP не перенаправляется | Нет серверного блока на порту 80 или он отдаёт сайт. Добавьте перенаправление |
Регулярная проверка
- Раз в сутки проверяйте срок сертификатов всех сервисов и оповещайте за 14 дней: мониторинг в Zabbix или скрипт по расписанию: проверка доступности порта в Zabbix.
- После каждого изменения конфигурации веб-сервера выполняйте проверки из статьи.
- Включите проверку TLS в реестр активов: срок сертификатов, ответственный, способ продления: реестр ИТ-активов.
Где это в модели зрелости
Материал относится к направлению «Сетевая безопасность» (материалы направления, карта зрелости). Контроль конфигурации публичных сервисов, включая сертификаты и версии протоколов, входит в требования к уровню 2.
Как проверить
- Для каждого публичного сервиса сертификат действует не менее 14 дней, имя совпадает, цепочка полная (код 0).
- Принимаются только TLS 1.2 и 1.3, TLS 1.1 отклоняется.
- HTTP перенаправляется на HTTPS, на HTTPS включён HSTS.
- Срок сертификатов под автоматическим контролем с оповещением.
Источники
- Методика оценки уровня зрелости кибербезопасности компании, Группа Сбер: sberbank.ru.
- Документация OpenSSL:
s_client,x509: docs.openssl.org. - Документация curl: curl.se.
- NIST SP 800-52 Rev. 2, Guidelines for the Selection, Configuration, and Use of TLS Implementations: csrc.nist.gov. Международная практика, не российский норматив.






















