1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6

# конспект · шаг 6 из 6

Конспект: сертификат и цепочка

выжимка - её можно унести в заметки

Что лежит в файлах сертификата и почему «работает у меня, не работает у интеграции».

Минимум

listen 443 ssl;
ssl_certificate     /etc/letsencrypt/live/shop.local/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/shop.local/privkey.pem;

Что где после certbot

cert.pem       сертификат сервера
chain.pem      промежуточные
fullchain.pem  cert.pem + chain.pem   ← ЭТО в ssl_certificate
privkey.pem    приватный ключ         ← это в ssl_certificate_key

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

$  команда
openssl s_client -connect shop.local:443 -servername shop.local </dev/null 2>/dev/null | openssl x509 -noout -dates -subject

Смотрят три вещи: срок, имена в SAN и полноту цепочки.

Замер на одном и том же сертификате, где имя стоит только в CN: curl отвечает 200, а Chrome - ERR_CERT_COMMON_NAME_INVALID. OpenSSL смотрит на CN, когда SAN нет вовсе; браузеры этот запасной путь убрали.

Сломанная цепочка (cert.pem вместо fullchain.pem) видна так же по-разному: openssl s_client пишет Verify return code: 21, curl - unable to get local issuer certificate (20), а десктопный браузер часто открывает сайт как ни в чём не бывало.

Рукопожатие: порядок

ClientHello (имя сайта открытым текстом = SNI, версии, шифры, список протоколов)
   → выбор server-блока и сертификата
ServerHello + сертификат + Finished        ← в 1.3 всё одной пачкой, один круг
Finished от клиента, следом первый запрос

TLS 1.3 - один круг, сертификат уходит зашифрованным. TLS 1.2 - два круга, сертификат виден открыто. Замер при задержке 50 мс: 163 против 210 мс на первый ответ.

Ошибка сертификата в access_log не попадает: до HTTP дело не дошло.

Ловушки джокера

  • cert.pem вместо fullchain.pem. Сайт откроется в Chrome и сломается везде остальном: браузеры на десктопе дотягивают недостающее звено сами, а curl, мобильные приложения, Java-клиенты и платёжные шлюзы - нет. Симптом «у меня работает, а интеграция не подключается» почти всегда про это.
  • Имя не в SAN. Сертификат «на домен» без нужного поддомена даёт ошибку у всех клиентов, хотя файл валиден.
  • Ключ с правами 644. Приватный ключ читает только root: мастер открывает его до сброса привилегий.
  • Перепутанная пара даёт SSL_CTX_use_PrivateKey ... key values mismatch, и пока конфиг не проходит проверку, reload не применяется - сайт продолжает работать со старым сертификатом, а ты думаешь, что уже с новым.
  • Сертификат живёт в памяти процесса. Замер: подменили файлы - отдаётся старый серийный номер, сделали reload - новый. Отсюда --deploy-hook.
  • SNI и Host - разные вещи и совпадать не обязаны: сертификат выбирается до HTTP-запроса. Поэтому openssl s_client без -servername показывает сертификат блока по умолчанию, а ssl_reject_handshake on в таком блоке отвечает предупреждением 112 и не отдаёт сертификата вовсе.
  • Wildcard покрывает один уровень и не покрывает сам домен - оба факта проверены: a.shop.local да, a.b.shop.local и shop.local нет.

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

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