// Engineering Log

HTTP, HTTPS и TLS: Часть 6 — Что такое ECH (Encrypted Client Hello) и как он скрывает имя сайта

Опубликовано 07.10.2026

// Быстрый маршрут

Эта статья относится к теме Серверы и инфраструктура.

ECH (Encrypted Client Hello) — расширение TLS 1.3, которое шифрует первое сообщение рукопожатия, ClientHello. Главное, что оно скрывает, — имя сайта в поле SNI. Без ECH любой узел между вами и сервером видит, что вы открыли shop.example.ru, даже если всё остальное зашифровано. С ECH наблюдатель видит только общее имя, одинаковое для многих сайтов за одним сервером или CDN. Стандарт опубликован в марте 2026 года как RFC 9849, а способ публикации ключей в DNS — как RFC 9848.

Что остаётся открытым без ECH

Рукопожатие TLS 1.3 шифрует почти всё, включая сертификат сервера. Но ClientHello клиент отправляет до того, как стороны договорились о ключах, поэтому он идёт открытым текстом и содержит:

  • SNI — имя сайта;
  • ALPN — список протоколов (h2, http/1.1), по которому можно понять тип приложения;
  • набор шифров, групп и расширений, по которому строятся отпечатки клиента (JA3, JA4).

Именно по SNI работают блокировки сайтов на оборудовании DPI, фильтры корпоративных сетей и родительский контроль у провайдеров. Раньше была попытка шифровать только SNI (ESNI, 2018), но она оставляла открытыми остальные поля и так и не стала стандартом. ECH — её замена: шифруется весь ClientHello целиком.

Как это работает

Два ClientHello в одном. Клиент формирует:

  • внутренний ClientHello — настоящий, с именем нужного сайта и полным списком ALPN;
  • внешний ClientHello — открытый, с общим именем (public_name), например cloudflare-ech.com. Внутренний лежит в нём зашифрованным в расширении encrypted_client_hello.

Внешний ClientHello видят все, внутренний может прочитать только сервер, у которого есть закрытый ключ ECH.

Откуда клиент берёт ключ. Сервер публикует конфигурацию ECH (ECHConfigList: открытый ключ, алгоритмы и public_name) в DNS-записи типа HTTPS для своего домена:

bash
dig +short HTTPS example.ru
1 . alpn="h3,h2" ipv4hint=192.0.2.10 ech=AEX+DQBBpQAgACB...

Браузер запрашивает эту запись вместе с A/AAAA и, если в ней есть параметр ech, шифрует ClientHello. Шифрование — по схеме HPKE (RFC 9180): клиент выводит одноразовый ключ из открытого ключа сервера.

Что делает сервер. Он расшифровывает внутренний ClientHello и продолжает рукопожатие с ним, как будто внешнего не было. В ответе клиенту сервер незаметно для наблюдателя подтверждает, что ECH принят.

Если ключ устарел. Ключи ECH периодически меняют. Если клиент зашифровал ClientHello старым ключом, сервер не сможет его расшифровать и завершит рукопожатие по внешнему ClientHello — с сертификатом для public_name — и передаст клиенту актуальную конфигурацию (retry configs). Клиент переподключается с новым ключом. Поэтому серверу нужен действующий сертификат и для общего имени.

Две схемы размещения:

  • shared mode — один сервер и расшифровывает ECH, и обслуживает сайты; так работает Cloudflare и так ECH поддерживается в Nginx;
  • split mode — отдельный фронт только расшифровывает ClientHello и передаёт соединение на сервер сайта, не видя содержимого. Подходит, когда фронт и сайты принадлежат разным владельцам.

GREASE ECH. Браузеры с поддержкой ECH отправляют расширение encrypted_client_hello со случайными данными даже тем сайтам, у которых ECH нет. Это нужно, чтобы по наличию расширения нельзя было отличить настоящий ECH от обычного соединения, и чтобы промежуточное оборудование не научилось ломаться на незнакомом расширении.

Что ECH скрывает, а что нет

ECH скрывает имя сайта от пассивного наблюдателя, но только при нескольких условиях:

  • DNS тоже зашифрован. Если запрос example.ru HTTPS ушёл обычным DNS, имя видно в нём. ECH имеет смысл вместе с DNS-over-HTTPS или DNS-over-TLS. Firefox использует ECH только при включённом DoH.
  • За адресом много сайтов. Если на IP-адресе один сайт, имя выдаёт сам адрес. Поэтому ECH по-настоящему работает у CDN и крупных хостингов, где под одним адресом тысячи доменов.
  • Внешний вид соединения. Длина ответа, время, наличие расширения — всё это остаётся доступно для анализа трафика.

ECH не скрывает IP-адрес сервера и не является средством обхода блокировок: заблокировать можно сам факт использования ECH или весь адрес провайдера.

Где ECH работает сегодня

  • Браузеры: Chrome с версии 117 и Firefox с версии 119 (2023) используют ECH по умолчанию, если находят конфигурацию в DNS.
  • Cloudflare включил ECH для сайтов на бесплатных тарифах в 2023 году, отключил из-за проблем и вновь начал раскатку в сентябре 2024-го. Для него public_name — cloudflare-ech.com.
  • OpenSSL поддерживает ECH с версии 4.0 (апрель 2026). Раньше ECH был только в отдельной ветке OpenSSL, в BoringSSL (Chrome) и NSS (Firefox).
  • Nginx получил ECH в версии 1.29.4 (директива ssl_ech_file, режим shared mode), при сборке с OpenSSL, поддерживающим ECH.
  • curl — ключ --ech с версии 8.8.0 как экспериментальная функция, при сборке с библиотекой TLS, умеющей ECH.

ECH в России

5–6 ноября 2024 года ТСПУ начали блокировать соединения с Cloudflare, в которых есть расширение ECH, — вместе с public_name cloudflare-ech.com. Роскомнадзор пояснил, что использование ECH нарушает российское законодательство, и рекомендовал владельцам сайтов не пользоваться CDN Cloudflare. На практике у пользователей с включённым ECH перестали открываться многие сайты на Cloudflare, никак не связанные с политикой.

Для владельца сайта с аудиторией из России из этого следует:

  • если сайт стоит за Cloudflare и часть посетителей жалуется на недоступность, проверьте, включён ли ECH в разделе SSL/TLS → Edge Certificates (на бесплатном тарифе выключатель доступен не всегда — тогда через API или поддержку);
  • включать ECH на собственном сервере для российской аудитории нет смысла: пользы в скрытии имени нет, а риск блокировки соединения есть.

Как включить ECH в Nginx

Нужны Nginx 1.29.4 или новее и OpenSSL 4.0 или новее. Готовых пакетов пока мало, поэтому Nginx обычно собирают из исходников с ключом --with-openssl=<путь к исходникам OpenSSL 4>.

1. Сгенерировать ключ ECH. Файл содержит закрытый ключ и конфигурацию для публикации в DNS:

bash
openssl ech -public_name ech.example.ru -out /etc/nginx/ech/ech.example.ru.pem.ech

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

2. Подключить ключ. Директиву удобно задать на уровне http, тогда она действует для всех сайтов:

nginx
http {
    ssl_ech_file /etc/nginx/ech/ech.example.ru.pem.ech;

    log_format ech '$remote_addr "$request" $status '
                   'ech=$ssl_ech_status outer=$ssl_ech_outer_server_name sni=$ssl_server_name';

    server {
        listen 443 ssl;
        server_name ech.example.ru;
        ssl_certificate     /etc/letsencrypt/live/ech.example.ru/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/ech.example.ru/privkey.pem;
        return 404;
    }

    server {
        listen 443 ssl;
        server_name shop.example.ru;
        ssl_certificate     /etc/letsencrypt/live/shop.example.ru/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/shop.example.ru/privkey.pem;
        access_log /var/log/nginx/shop.access.log ech;
        root /var/www/shop;
    }
}

Переменная $ssl_ech_status принимает значения SUCCESS (ECH принят), NOT_TRIED (клиент не пробовал), GREASE (клиент прислал пустышку), FAILED и BACKEND.

3. Опубликовать конфигурацию в DNS. Строку в Base64 из файла .pem.ech (блок ECHCONFIG) добавьте в HTTPS-запись каждого сайта:

shop.example.ru.  300  IN  HTTPS  1 . alpn="h2,http/1.1" ech="AEX+DQBBpQAgACB..."

Не все DNS-хостинги позволяют создавать записи типа HTTPS; у кого нельзя — ECH не заработает.

4. Менять ключи. Ключ ECH стоит обновлять раз в несколько недель: сгенерировать новый, добавить его в Nginx рядом со старым (директиву можно повторить), опубликовать в DNS, выждать TTL, убрать старый.

Как проверить

В браузере. Страница https://crypto.cloudflare.com/cdn-cgi/trace показывает строку sni=encrypted, если ECH сработал, и sni=plaintext, если нет. На собственном сайте результат виден в журнале по переменной $ssl_ech_status.

Через curl (нужна сборка с ECH):

bash
curl --ech true https://shop.example.ru/     # пробовать ECH, при неудаче — без него
curl --ech hard https://shop.example.ru/     # только ECH, иначе ошибка
curl --ech ecl:AEX+DQBBpQAgACB... https://shop.example.ru/   # конфигурация вручную, без DNS
curl --ech false https://shop.example.ru/    # не использовать ECH

curl берёт конфигурацию из HTTPS-записи через DoH, поэтому вместе с --ech обычно указывают --doh-url https://dns.example.net/dns-query.

Через openssl (4.0 и новее):

bash
openssl s_client -connect shop.example.ru:443 -servername shop.example.ru \
  -ech_config_list AEX+DQBBpQAgACB...

Со стороны сети. В Wireshark у соединения с ECH в SNI будет public_name, а в ClientHello — расширение encrypted_client_hello (тип 0xfe0d) с большим блоком данных.

Типичные ошибки

  • ECH включён, а DNS у клиента обычный — имя сайта всё равно видно в DNS-запросе.
  • Нет сертификата на public_name — клиенты со старым ключом не могут получить новый и отваливаются.
  • Ключ сменили на сервере, но не обновили в DNS, или наоборот — клиенты получают ошибку до истечения TTL.
  • ECH на отдельном сервере с одним сайтом: имя не видно в SNI, но однозначно определяется по IP-адресу.
  • ECH включён для сайта с аудиторией в России — часть посетителей теряет доступ из-за блокировки.

// Похожая задача

Если у вас похожая ситуация

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

Тема статьи

Серверы и инфраструктура

VPS, Linux, веб-стек, миграции, хостинг, базы данных и базовая эксплуатация.

Часто с этим приходят

  • Перенести сайт или сервис на новый сервер
  • Настроить Linux, Nginx, базу данных и бэкапы
  • Разобраться, почему всё работает нестабильно

// Следующий шаг

Если вам нужна не только статья, а помощь по этой теме, удобнее сразу перейти в услугу. Главная и подборка материалов остаются рядом.

Открыть услуги

// Reviews

Отзывы по теме

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

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

kireevk

kireevk

Консультация по nginx proxy manager и portainer

25.02.2025 · ★ 5/5

Освоившийся покупатель
apande

apande

Настройка nginx и opencart

07.09.2024 · ★ 5/5

Очень мощный покупатель
kireevk

kireevk

Диагностика Nginx Proxy Manager в docker контейнере и решение проблемы

15.03.2024 · ★ 5/5

Освоившийся покупатель

// Contact

Нужна помощь?

Свяжись со мной и я помогу решить проблему

Написать в Telegram

Отвечаю в течение рабочего дня (03:00–13:00 GMT)

Или оставьте заявку здесь:

Подтвердите, что вы не бот.

Написать и получить быстрый ответ