SSL и сайты

Как устроена цепочка доверия SSL-сертификата

Клиент доверяет сертификату сайта, когда может построить и проверить путь от конечного сертификата через промежуточные центры до знакомого корня.

Цепочка доверия SSL-сертификата — это проверяемый путь от конечного сертификата сайта через один или несколько промежуточных сертификатов к корневому сертификату, которому доверяет клиент. Браузер не верит сайту только потому, что сервер прислал файл с правильным доменом: он проверяет подписи, сроки, ограничения X.509, назначение ключей, имя узла и наличие подходящего trust anchor в своём хранилище.

Термин «SSL-сертификат» привычен, хотя современные HTTPS-соединения используют TLS. Сама цепочка относится к инфраструктуре открытых ключей X.509 и не шифрует трафик отдельно: она позволяет клиенту аутентифицировать серверный ключ, участвующий в TLS-соединении.

Три уровня цепочки

Типичная публичная цепочка состоит из трёх ролей.

Leaf, end-entity или конечный сертификат. Это сертификат конкретного сайта, например www.example.com. В нём находятся открытый ключ, срок действия, издатель и допустимые DNS-имена в Subject Alternative Name. Его закрытый ключ хранится у оператора сайта и не входит ни в сертификат, ни в цепочку, передаваемую клиенту.

Intermediate или промежуточный сертификат. Промежуточный центр сертификации подписывает leaf-сертификат. Его собственный сертификат подписан вышестоящим CA — другим intermediate или root. Такая архитектура позволяет держать ключ корневого центра вне повседневной выдачи и при необходимости заменить или отозвать ограниченную промежуточную ветку.

Root или корневой сертификат. Это якорь доверия. Корневой сертификат обычно самоподписан, но самоподпись не делает его автоматически доверенным. Доверие появляется потому, что конкретный root заранее включён в хранилище операционной системы, браузера, Java, контейнера или приложения согласно правилам соответствующей root-программы.

Схематично путь выглядит так:

www.example.com (leaf)
  -> Example Issuing CA (intermediate)
    -> Example Root CA (root / trust anchor)

Клиент проверяет подпись leaf открытым ключом intermediate, затем подпись intermediate ключом следующего издателя и ограничения каждого сертификата. Финальный root сопоставляется с локальным доверенным якорем. Одинаковый сервер поэтому может пройти проверку на одном устройстве и не пройти на другом: их хранилища и политики могут различаться.

Что сервер должен передавать

Во время TLS-рукопожатия сервер обычно отправляет leaf первым, а затем необходимые промежуточные сертификаты. Корневой сертификат обычно не отправляют: клиент уже должен доверять своей локальной копии. Если добавить root в ответ сервера, недоверяющий клиент не начнёт ему верить — иначе любой владелец самоподписанного корня мог бы назначить себя доверенным центром.

fullchain.pem — распространённое имя файла, а не отдельный тип сертификата в стандарте X.509. В конфигурациях ACME-клиентов он обычно содержит leaf и промежуточную часть в нужном порядке. Отдельный файл вроде cert.pem содержит только leaf. Конкретные имена файлов зависят от клиента и платформы, поэтому их назначение сверяют с документацией выпуска и веб-сервера.

Нельзя собирать fullchain случайным объединением всех найденных PEM-файлов. Серверу нужна цепочка, соответствующая выданному leaf. Лишние, устаревшие или неверно упорядоченные сертификаты увеличивают ответ, могут запутать несовместимые клиенты и не исправляют отсутствие нужного издателя. При наличии альтернативных или cross-signed цепочек выбирают вариант, который официально предлагает CA для требуемой аудитории.

Что такое неполная цепочка

Цепочка неполна, когда сервер не передал сертификат, необходимый клиенту для перехода от leaf к доверенному якорю. Самый частый случай — в настройке указан только cert.pem вместо fullchain. Клиент видит, кем подписан leaf, но не располагает сертификатом этого intermediate и прекращает построение пути.

Проблема может быть непостоянной. Браузер ранее сохранил intermediate, получил его с другого сайта или загрузил по адресу Authority Information Access. Утилита, мобильное приложение, Java runtime или минимальный контейнер могут этого не делать. В результате главная страница открывается у администратора, а API-клиент сообщает unable to get local issuer certificate, unable to verify the first certificate или обрывает TLS без понятного сообщения.

Есть и обратная ситуация: сервер передаёт полную последовательность, но нужного root нет в старом клиенте. Это уже не пропущенный intermediate, а вопрос доверенного хранилища или совместимости выбранной цепочки. Добавлять leaf либо intermediate в системные trusted roots ради быстрого устранения ошибки опасно: так меняется модель доверия устройства вместо исправления серверной конфигурации.

Проверка в браузере

Откройте точный HTTPS-hostname, на котором возникает проблема. В сведениях о сертификате найдите путь сертификации и проверьте:

  1. leaf соответствует имени из адресной строки по SAN;
  2. срок действия каждого элемента актуален;
  3. между leaf и доверенным root видны ожидаемые intermediate;
  4. браузер не сообщает об ограничениях назначения, подписи или доверия;
  5. тот же результат получается для example.com, www.example.com и других самостоятельных TLS-хостов.

Интерфейс показывает цепочку, которую построил браузер, а не обязательно точный список, присланный сервером. Поэтому успешной проверки в одном браузере недостаточно. Повторите тест в чистом профиле или на устройстве без накопленного кеша и дополните его независимой проверкой SSL-сертификата.

Проверка серверного ответа через OpenSSL

Следующая команда подключается с SNI, показывает сертификаты, присланные сервером, проверяет hostname и завершает соединение при ошибке верификации:

openssl s_client \
  -connect example.com:443 \
  -servername example.com \
  -showcerts \
  -verify_hostname example.com \
  -verify_return_error </dev/null

-servername явно фиксирует SNI для диагностируемого виртуального хоста. В OpenSSL 1.1.1 и новее SNI обычно автоматически берётся из DNS-имени в -connect, но явный параметр устраняет неоднозначность и необходим, если -connect содержит IP-адрес или другое имя. -showcerts выводит именно список, отправленный сервером, а не гарантированно построенную и проверенную цепочку. Смотрите секцию Certificate chain, значения subject и issuer, а также итоговый Verify return code.

Успех зависит от trust store той машины, где запущен OpenSSL. Если команда работает на сервере администратора, это не доказывает совместимость со всеми клиентами. И наоборот, ошибка на давно не обновлявшейся системе может быть связана с её корнями, а не с missing intermediate. Зафиксируйте версию OpenSSL и используемое хранилище при сравнении результатов.

Локальные файлы можно проверить с изолированным набором доверия:

openssl verify \
  -purpose sslserver \
  -trusted trusted-root.pem \
  -untrusted intermediate-chain.pem \
  leaf.pem

Здесь -trusted делает trusted-root.pem единственным набором trust anchors и отключает стандартные CA-файл, каталог и store. intermediate-chain.pem содержит недоверенные промежуточные сертификаты для построения пути, а leaf.pem — проверяемый сертификат. Команда проверяет цепочку и назначение sslserver, но не DNS-имя; при необходимости добавьте -verify_hostname example.com. Успех такой лабораторной проверки не означает, что публичные клиенты доверяют выбранному root.

Как исправить incomplete chain

  1. Определите, какой leaf реально отдаёт проблемный hostname с учётом SNI, CDN и балансировщика. Не полагайтесь только на файл в каталоге origin-сервера.
  2. Получите рекомендованную цепочку из официальной документации своего CA или повторно выгрузите артефакты через штатный ACME-клиент. Не скачивайте неизвестный bundle с форума.
  3. Укажите в TLS-конфигурации файл, содержащий leaf и требуемые intermediate. Закрытый ключ должен соответствовать leaf и оставаться отдельным защищённым файлом.
  4. Проверьте синтаксис конфигурации, примените её безопасным способом и снова запросите каждый hostname через OpenSSL.
  5. Протестируйте чистый браузер, критичные API-клиенты, мобильные приложения и контейнерные образы, которые входят в поддерживаемую аудиторию.
  6. Проверьте внешний HTTP-результат через проверку сайта, чтобы исключить другой TLS-терминатор или неожиданный редирект на хост с отдельной цепочкой.

Если сертификат установлен на нескольких узлах, обновляйте их согласованно. Частичная выкладка создаёт «плавающую» ошибку: один запрос попадает на сервер с fullchain, следующий — на узел только с leaf. Сравнивайте серийный номер и issuer на каждом адресе балансировки, но учитывайте, что легитимная инфраструктура может использовать разные действительные сертификаты.

Частые ошибки

  • Путать cert.pem и fullchain.pem и передавать только leaf.
  • Включать root в bundle в надежде создать доверие у клиента.
  • Считать -showcerts доказательством успешной верификации: эта опция лишь показывает отправленный список.
  • Запускать OpenSSL без правильного SNI и диагностировать сертификат другого сайта.
  • Проверять только срок leaf, не сверяя SAN, ограничения и весь путь.
  • Делать вывод по одному браузеру, который уже закешировал missing intermediate.
  • Устанавливать неизвестный CA в trusted store вместо исправления цепочки на сервере.
  • Обновлять origin, забывая, что публичный TLS завершается на CDN, ingress или load balancer.
  • Использовать старую цепочку после перевыпуска, хотя CA предоставил другой intermediate.
  • Игнорировать альтернативные хранилища Java, мобильной ОС и самостоятельного приложения.

Связанные инструменты

Проверка SSL-сертификата помогает увидеть фактический leaf, издателя, SAN и срок на публичном хосте. Проверка сайта показывает доступность конечного HTTPS-адреса и HTTP-статус после соединения. Для расследования incomplete chain сочетайте эти результаты с openssl s_client: инструменты видят сервер с разных клиентских окружений и отвечают на разные вопросы.

Частые вопросы

Нужно ли серверу отправлять корневой сертификат?

Обычно нет. Корневой сертификат уже должен находиться в доверенном хранилище клиента, а сервер передаёт конечный и необходимые промежуточные сертификаты. Отправка корня не создаёт доверие сама по себе.

Почему сайт открывается в браузере, но не работает в API или OpenSSL?

Браузер мог получить недостающий intermediate по ссылке AIA или сохранить его ранее, тогда как другой клиент использует только присланную сервером цепочку и своё хранилище корней. Также различаются версии, политики и поддерживаемые алгоритмы.

Чем fullchain отличается от сертификата сайта?

Файл сертификата сайта обычно содержит только leaf-сертификат, а fullchain — leaf и следующие за ним промежуточные сертификаты, необходимые серверу для передачи клиенту. Точный состав и порядок нужно брать из документации центра сертификации и серверного ПО.

Проверить на практике

Связанные термины

Источники

  1. RFC 5280: Internet X.509 Public Key Infrastructure Certificate and CRL Profile
  2. Let's Encrypt: Chains of Trust
  3. OpenSSL documentation: openssl-s_client
  4. OpenSSL documentation: openssl-verify
  5. OpenSSL documentation: verification options

Как проверить SSL-сертификат сайта

Проверка сертификата не ограничивается датой окончания: важны имя узла, цепочка до доверенного центра и фактическая конфигурация TLS-сервера.