RE:NODE

Веб-хостинг11 мин чтения

HTTPS и Let's Encrypt: как ACME выпускает ваш сертификат

Что доказывает сертификат, как работает проверка ACME, почему продление автоматическое и несколько причин, по которым выпуск не проходит на настоящем домене.

0 прочтений

Сертификат - это файл, который говорит: «этот открытый ключ принадлежит тому, кто управляет example.com», и подписан центром сертификации, которому браузеры уже доверяют. Let's Encrypt раздаёт их бесплатно, потому что интересна не сама бумага, а доказательство: автоматический обмен под названием ACME, в котором центр сертификации ставит вам небольшую задачу, справиться с которой может только настоящий владелец имени. Пройдёте её - получите сертификат на 90 дней. Автоматизируете прохождение - и больше никогда не думаете о сертификатах.

Здесь описано, что происходит во время этого обмена, что его ломает и что вам всё равно приходится делать самим после появления замка.

Что на самом деле доказывает сертификат#

Меньше, чем думают большинство. Обычный сертификат Let's Encrypt - это сертификат с проверкой домена: единственное, что он утверждает, - тот, кто его запросил, смог в тот момент продемонстрировать контроль над доменным именем. Он ничего не говорит о том, кто владеет сайтом, существует ли компания и честен ли сайт. Фишинговый сайт может получить и получает действительный сертификат за тридцать секунд.

То, что он даёт, тем не менее ценно:

  • Шифрование. Никто между посетителем и сервером не может прочитать или изменить трафик. В общей сети wifi это разница между приватным и публичным сеансом.
  • Целостность. Посредник не может внедрить в страницу скрипт, редирект или рекламу.
  • Подлинность для имени. Посетитель разговаривает с той машиной, на которую указывает DNS, а не с тем, кто ответил первым.

Сертификаты с проверкой организации и расширенной проверкой существуют, стоят денег и подразумевают, что человек сверяет реестры компаний. Их стоит покупать, если этого требует договор. Браузеры перестали показывать название компании в адресной строке в 2019 году, так что видимая выгода теперь нулевая.

Обмен ACME шаг за шагом#

ACME - это протокол (RFC 8555) между клиентом на вашей стороне и центром сертификации. Certbot - один из клиентов, ваша панель хостинга запускает другой, и шаги одинаковы независимо от того, какой из них.

  1. Аккаунт. Клиент генерирует пару ключей и регистрирует её в центре сертификации. Это происходит один раз и с этого момента идентифицирует вас.
  2. Заказ. Клиент запрашивает сертификат на одно или несколько имён: example.com, www.example.com.
  3. Авторизация и проверка. Для каждого имени центр отвечает токеном и списком способов доказать контроль.
  4. Подготовка. Клиент публикует ответ - файл на вашем веб-сервере или запись DNS.
  5. Валидация. Клиент сообщает центру, что готов. Центр со своей стороны разрешает имя, забирает ответ и проверяет его. Именно этот шаг падает, и падает потому, что центр видит не то, что видите вы.
  6. Завершение. Клиент отправляет запрос на подпись сертификата с открытым ключом, который будет использовать. Центр его подписывает.
  7. Загрузка. Клиент забирает сертификат и промежуточную цепочку, устанавливает их и перезагружает веб-сервер.
заказ для example.comтокен и проверказаписывает файл токенакуда указывает имя?GET по пути токенаподписанный сертификатACME-клиентна вашем сервереПубличный DNSA-запись имениВаш веб-серверпорт 80, путь well-knownЦентр сертификациипроверяет и подписывает
Проверка HTTP-01: от заказа до сертификата

Главное на этой картинке в том, что центр проверяет из публичного интернета, используя публичный DNS. Ваш файл /etc/hosts, ваш VPN, кэш вашего браузера и тот DNS, который случайно использует ваш ноутбук, не имеют значения. Если для остального мира имя разрешается в старый хост, выпуск не пройдёт, как бы ни был правилен новый сервер.

Три типа проверки#

ПроверкаЧто нужноWildcardТипичное применение
http-01Доступный порт 80, файл в /.well-known/acme-challenge/НетПочти любой обычный сайт
dns-01Запись TXT в _acme-challenge.<name>ДаWildcard, серверы без публичного порта 80
tls-alpn-01Порт 443 и контроль над слушателем TLSНетПрокси и балансировщики, которые сами занимают 443

HTTP-01 - вариант по умолчанию. Клиент записывает файл, имя которого - токен, а содержимое - токен плюс хэш вашего ключа аккаунта, а центр запрашивает http://example.com/.well-known/acme-challenge/<token> по обычному HTTP на порту 80. Он следует редиректам, поэтому сайт, который всё отправляет на HTTPS, обычно в порядке, а правило, возвращающее для этого пути 404, страницу входа или блокировку WAF, - нет.

DNS-01 - единственный способ получить wildcard вроде *.example.com и единственный вариант, когда порт 80 закрыт или машина вообще недоступна публично. Цена в том, что для его автоматизации нужен API-токен вашего DNS-провайдера, а из-за распространения DNS каждое продление идёт медленнее. Учтите, что wildcard покрывает один уровень: *.example.com подходит для app.example.com, но не для a.b.example.com.

TLS-ALPN-01 доказывает контроль над портом 443, отвечая на особое рукопожатие по протоколу acme-tls/1. Вы столкнётесь с ним, только если у вас прокси, который сам обрабатывает TLS.

Большинство людей вообще не выбирают. Клиент берёт HTTP-01, он работает, и выбор становится интересным, только когда вам нужен wildcard.

Продление и окно, которое важно#

Сертификаты Let's Encrypt живут 90 дней. Это сделано намеренно: короткий срок заставляет автоматизировать, а автоматизация устраняет ежегодную аварию, когда кто-то забыл. Продление - не особая операция, а тот же обмен ещё раз, от заказа до загрузки.

Клиенты продлевают заранее, чтобы оставался запас на неудачу. Таймер Certbot запускается дважды в день и продлевает всё, у чего осталось 30 дней или меньше, а это оставляет месяц на повторные попытки, прежде чем что-то станет видно пользователям. Панели, которые делают это за вас, используют собственное окно: на RE:NODE запланированная задача продлевает любой сертификат, попавший в окно 21 день, без запроса, так что одна неудачная попытка - это не инцидент.

Что вам всё же стоит делать:

  • Следите за сроком снаружи. Больнее всего бьёт продление, которое неделями тихо не удаётся. Проверяйте живой сертификат с другой машины, а не файл на диске.
  • Знайте, что перезагружает сервер. Продлённый сертификат на диске ничего не делает, пока веб-сервер его не прочитает. Certbot решает это через deploy hook; панель делает это за вас.
  • Ничего не закрепляйте. HPKP мёртв, а закрепление сертификата в мобильном приложении за 90-дневным сертификатом - это запланированный простой.
bash
$ echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \    | openssl x509 -noout -subject -issuer -dates

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

Запуск клиента ACME самостоятельно#

На вашем собственном сервере certbot - вариант по умолчанию, и плагин для nginx делает всю работу, включая правку блока server и перезагрузку:

bash
$ certbot --nginx -d example.com -d www.example.com$ certbot renew --dry-run

Если вы хотите, чтобы он только получил файлы и не трогал вашу конфигурацию, используйте метод webroot и укажите каталог, из которого отдаётся ваш сайт:

bash
$ certbot certonly --webroot -w /var/www/site -d example.com -d www.example.com

В любом случае результат окажется в /etc/letsencrypt/live/example.com/:

ФайлЧто этоДля чего использовать
privkey.pemВаш закрытый ключssl_certificate_key
fullchain.pemКонечный сертификат плюс промежуточныйssl_certificate
cert.pemТолько конечный сертификатПочти никогда
chain.pemТолько промежуточныйНастройка stapling

Используйте fullchain.pem. Отдавать один cert.pem - классическая ошибка: она работает в вашем браузере, потому что он закэшировал промежуточный сертификат с какого-то другого сайта, и падает у посетителя, чей браузер этого не сделал. Единственная надёжная проверка - зайти с машины, которая никогда не открывала сайт.

certbot renew --dry-run прогоняет всё продление в тестовой среде. Запускайте его после любого изменения конфигурации сервера, потому что узнавать, что продление сломано, нужно не через 89 дней.

На управляемом хостинге вы ничего из этого не делаете. Тарифы RE:NODE для приложений и сайтов содержат слот прокси: направьте запись A на адрес, показанный на вкладке, и сертификат будет выпущен и продлён за вас. Ваше приложение никогда не видит сертификат, никогда не слушает 443 и получает настоящий адрес посетителя в X-Forwarded-For; путь запроса разобран в статье что делает обратный прокси.

Смешанное содержимое, редиректы и HSTS#

Замок - это ещё не конец работы. Обычно остаются три вещи.

Смешанное содержимое. Страница, загруженная по HTTPS, которая запрашивает скрипт, стиль или iframe по HTTP, блокируется любым современным браузером наотрез; изображения и медиа обычно повышаются до HTTPS или блокируются с предупреждением. Решение - перестать генерировать URL с http://. В CMS это значит база данных, где абсолютные URL были сохранены много лет назад: выполните настоящий поиск с заменой по всему содержимому, а не правьте страницы вручную, и проверьте жёстко прописанные URL в шаблонах темы. Content-Security-Policy: upgrade-insecure-requests - полезный заголовок «на всякий случай», пока вы наводите порядок, но не замена самой уборки.

Редирект. Если отдавать обе схемы, половина ваших ссылок окажется не той. Отправляйте всё на HTTPS на уровне сервера:

nginx
server {    listen 80;    server_name example.com www.example.com;    return 301 https://example.com$request_uri;}

Это заодно сворачивает www в apex за один переход, что вам и нужно: в какую сторону это делать и почему цепочки редиректов вам дорого обходятся, описано в статье www или apex: домен и редиректы.

HSTS. Strict-Transport-Security велит браузеру на некоторый срок отказываться от обычного HTTP для этого имени, а это закрывает брешь, когда первый запрос за день уходит без шифрования.

nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

Начните с короткого max-age, например 300, пока вы убеждаетесь, что ничто на сайте не нуждается в HTTP, затем увеличивайте. includeSubDomains применяется к каждому поддомену, включая те, о которых вы забыли, а preload вносит имя в список, встроенный в браузеры, и отменять это медленно и неудобно. HSTS - единственный заголовок из этих, который при ошибке может отключить сайт от эфира, поэтому добавляйте его последним и сознательно.

Когда выпуск не проходит#

Почти каждый сбой - одно из следующего, в порядке вероятности.

Имя ещё не разрешается в этот сервер. Вы добавили запись пять минут назад, а старое значение всё ещё в кэше, либо вы правили зону у провайдера, который больше не авторитетен. Проверьте снаружи вашей сети командой dig +short example.com @1.1.1.1 и сравните с адресом, который вам выдали. Какая запись куда относится, объясняет статья DNS-записи простыми словами, а случай, когда вы правите зону, которую никто не читает, - статья неймсерверы или DNS-записи.

Порт 80 закрыт. HTTP-01 он нужен, хотя готовый сайт использует только 443. Правило файрвола или хост, который пробрасывает только 443, провалит каждую попытку с таймаутом соединения.

Что-то перехватывает путь проверки. CDN впереди, страница обслуживания, фреймворк, который отправляет все неизвестные пути в обработчик 404, слой аутентификации над всем сайтом. /.well-known/acme-challenge/ должен отдавать файл без аутентификации.

Запись CAA это запрещает. Запись CAA перечисляет, каким центрам разрешено выпускать сертификаты для вашего домена, и центр проверяет её при выпуске. Если она у вас есть и не называет центр, которым пользуется ваш хостер, выпуск завершится ошибкой CAA. Проверьте командой dig CAA example.com, а если вы на управляемом хостинге, спросите поддержку, какой центр разрешить, вместо того чтобы гадать.

Домен стоит за прокси, который отвечает первым. При включённом CDN с оранжевым облаком центр сертификации достаёт до CDN, а не до вас. Это нормально, когда выпуском занимается CDN, и проблема, когда выпускает ваш origin. Какой слой держит какой сертификат, разобрано в статье Cloudflare для сайтов и игровых серверов.

Вы упёрлись в лимит. Let's Encrypt ограничивает, сколько сертификатов может получить зарегистрированный домен в неделю и сколько одинаковых сертификатов вы можете запросить. Опубликованные цифры включали 50 сертификатов на зарегистрированный домен в неделю и 5 дубликатов, и они меняются, так что прочитайте актуальные лимиты, прежде чем писать цикл повторных попыток. Тестируйте на тестовой среде, где лимиты намного мягче и где выпускаются сертификаты, которым браузеры не доверяют.

FAQ#

Бесплатный сертификат так же хорош, как платный?

Для шифрования - идентичен. Сертификат Let's Encrypt использует те же алгоритмы и пользуется доверием тех же браузеров, что и платный сертификат с проверкой домена. Вы платите за проверку организации, гарантию или договор поддержки, а не за более сильное шифрование.

Почему 90 дней, а не год?

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

Нужен ли сертификат сайту без входа по логину?

Да. Браузеры помечают обычный HTTP как небезопасный, поисковые системы предпочитают HTTPS, а современные возможности браузера, от геолокации до service worker, отказываются работать без него. И не бывает страницы настолько скучной, чтобы её нельзя было подменить в пути.

Что происходит, когда срок сертификата истекает?

Посетители получают полноэкранное предупреждение, которое нужно обойти вручную, а всё автоматическое - клиент API, отправитель webhook, мобильное приложение - просто перестаёт работать. Льготного периода нет. Поэтому окна продления измеряются неделями, а не днями.

Может ли один сертификат покрывать несколько доменов?

Да. Сертификат может перечислять несколько имён в поле subject alternative name, так что example.com, www.example.com и shop.example.net могут делить один. Wildcard покрывает все прямые поддомены одного имени, но для него нужна проверка через DNS.

Почему сайт пишет «не защищено», хотя сертификат действителен?

Почти всегда - смешанное содержимое. Сертификат в порядке, а страница загружает что-то по обычному HTTP. Откройте консоль браузера: она назовёт точный URL, который блокируется.


Комментарии

Полностью анонимно: без аккаунта, без почты, без cookie. Мы храним имя, которое вы ввели, текст и время - больше ничего. Количество ссылок ограничено, разметка не отображается.

0/2000