Модуль: Сети и протоколы · Уровень: Middle+/Senior

TL;DR#

  • TLS даёт конфиденциальность (шифрование), целостность (MAC/AEAD) и аутентификацию (сертификаты) поверх TCP.
  • TLS 1.3 — 1-RTT handshake (vs 2-RTT в 1.2), 0-RTT на возобновлении, выкинул небезопасные шифры (RSA key exchange, CBC, RC4), всегда forward secrecy (ECDHE).
  • Доверие — через цепочку сертификатов до доверенного корневого CA; сервер шлёт leaf + промежуточные, клиент проверяет до корня.
  • SNI позволяет хостить много доменов на одном IP (выбор сертификата); ALPN согласует протокол (h2/h3/http1.1) в рамках handshake.
  • mTLS — взаимная аутентификация: клиент тоже предъявляет сертификат (zero-trust, service mesh).
  • В Go всё в crypto/tls: tls.Config, tls.Certificate, RootCAs, ClientCAs, ServerName, NextProtos.

Теория#

Что даёт TLS#

  1. Конфиденциальность — симметричное шифрование сессии (AES-GCM, ChaCha20-Poly1305).
  2. Целостность — AEAD (шифрование + аутентификация в одном).
  3. Аутентификация — проверка сертификата сервера (и опц. клиента) через PKI.

Handshake: TLS 1.2 vs 1.3#

TLS 1.2 (2-RTT):

ClientHello (cipher suites, random) ->
                <- ServerHello (выбранный cipher, random)
                <- Certificate, ServerKeyExchange, ServerHelloDone
ClientKeyExchange, ChangeCipherSpec, Finished ->
                <- ChangeCipherSpec, Finished
[данные]

TLS 1.3 (1-RTT):

ClientHello (+ key_share: уже шлёт ECDHE-параметры) ->
                <- ServerHello (+ key_share), {Certificate, Finished}
{Finished} ->  [данные уже можно слать]

Ключевые отличия 1.3:

  • 1-RTT вместо 2 (клиент сразу шлёт key_share — угадывает группу).
  • 0-RTT resumption: при возобновлении данные летят в первом же сообщении (но replay-риск — нельзя для не-идемпотентных операций).
  • Только forward secrecy: статический RSA key exchange удалён, всегда (EC)DHE — компрометация ключа сервера не раскрывает прошлый трафик.
  • Выкинуты слабые примитивы: RC4, CBC-mode, SHA-1, сжатие (CRIME), renegotiation.
  • Бóльшая часть handshake шифруется (включая сертификат сервера).

Сертификаты и цепочка доверия#

  • Сертификат X.509: публичный ключ + subject (CN/SAN) + издатель + срок + подпись CA.
  • Цепочка: leaf (сервера) → intermediate CA(s) → root CA. Клиент имеет хранилище доверенных корней; проверяет подписи по цепочке до корня.
  • Сервер обязан слать leaf + ВСЕ промежуточные (root клиент имеет сам). Забытый intermediate → “unable to get local issuer certificate” у части клиентов.
  • Имя проверяется по SAN (Subject Alternative Name), CN устарел (современные клиенты CN игнорируют).
  • Отзыв: CRL (списки) и OCSP; OCSP stapling — сервер прикладывает свежий OCSP-ответ к handshake (экономит обращение клиента к CA).

SNI (Server Name Indication)#

  • Расширение ClientHello: клиент в открытом виде указывает запрашиваемый hostname до установки шифрованного канала.
  • Позволяет одному IP/порту обслуживать много доменов с разными сертификатами (virtual hosting по TLS).
  • ECH (Encrypted Client Hello) — современное расширение, прячет SNI (раньше hostname утекал в открытом виде).

ALPN (Application-Layer Protocol Negotiation)#

  • Расширение handshake: клиент шлёт список протоколов (h2, http/1.1, h3), сервер выбирает.
  • Так согласуется HTTP/2 без лишнего RTT. Go-сервер использует это для авто-h2.

mTLS (взаимный TLS)#

  • Сервер дополнительно запрашивает сертификат клиента (CertificateRequest), клиент предъявляет, сервер валидирует по своему ClientCAs.
  • Применение: service-to-service в zero-trust/service mesh (Istio/Linkerd), API с сильной аутентификацией, замена/дополнение API-ключей.

TLS в Go#

// Сервер с mTLS
caPool := x509.NewCertPool()
caPool.AppendCertsFromPEM(caPEM)
cfg := &tls.Config{
    MinVersion:   tls.VersionTLS12,            // не ниже 1.2
    ClientAuth:   tls.RequireAndVerifyClientCert, // mTLS
    ClientCAs:    caPool,
    NextProtos:   []string{"h2", "http/1.1"},  // ALPN
}
srv := &http.Server{Addr: ":443", TLSConfig: cfg, Handler: mux}
srv.ListenAndServeTLS("server.crt", "server.key")
// Клиент
clientCert, _ := tls.LoadX509KeyPair("client.crt", "client.key")
tr := &http.Transport{
    TLSClientConfig: &tls.Config{
        RootCAs:      caPool,         // кому доверяем
        Certificates: []tls.Certificate{clientCert}, // для mTLS
        ServerName:   "api.internal", // для SNI/проверки имени
        // InsecureSkipVerify: true,  // НИКОГДА в проде
    },
}
client := &http.Client{Transport: tr}
  • tls.Config.GetCertificate — выбор сертификата по SNI динамически (SNI-роутинг).
  • Сессионный ресампл и ClientSessionCache — переиспользование TLS-сессий клиентом.

Подводные камни / gotchas#

  • InsecureSkipVerify: true отключает ВСЮ проверку (имя + цепочка) → MITM. Частая “временная заплатка”, остающаяся навсегда. Для самоподписанных правильно — добавить CA в RootCAs.
  • Забытый intermediate-сертификат: работает в браузере (он догружает AIA), падает у строгих клиентов (Go не догружает AIA по умолчанию). Всегда отдавайте full chain.
  • Истёкший сертификат — классический инцидент; нужен мониторинг срока и авто-renew (cert-manager, ACME/Let’s Encrypt).
  • 0-RTT replay: данные из 0-RTT можно переиграть → запрещено для не-идемпотентных запросов (POST с побочными эффектами).
  • SNI утечка: hostname в ClientHello открыт (до ECH) — не “секрет”, виден на сетевом уровне.
  • Clock skew: рассинхронизация часов ломает проверку срока (not before/not after).
  • Несовпадение SAN: сертификат на example.com, обращение по IP или *.example.com к глубокому поддомену → ошибка. Wildcard покрывает один уровень.
  • mTLS и ротация клиентских сертов: протухший клиентский серт = массовый отказ; нужна автоматизация ротации.
  • Слишком новый MinVersion у клиента vs старый сервер — handshake failure; следить за совместимостью.

Вопросы на собеседовании#

В: Чем TLS 1.3 принципиально лучше 1.2? О: 1-RTT handshake (vs 2), 0-RTT на возобновлении, обязательный forward secrecy (только ECDHE, RSA key exchange удалён), выпилены слабые шифры/режимы (CBC, RC4, сжатие, renegotiation), шифрование большей части handshake включая сертификат.

В: Что такое forward secrecy и почему 1.3 его гарантирует? О: Компрометация долгоживущего ключа сервера не позволяет расшифровать ранее перехваченный трафик. Достигается эфемерным обменом ключами (ECDHE) — сессионный ключ не выводится из ключа сертификата. В 1.3 статический RSA key exchange удалён, поэтому FS всегда.

В: Как работает цепочка доверия и что должен слать сервер? О: Leaf подписан intermediate CA, тот — root CA, которому клиент доверяет (в хранилище корней). Сервер должен прислать leaf + все промежуточные; root у клиента уже есть. Без intermediate строгие клиенты не построят цепочку.

В: Зачем нужен SNI? О: Клиент в ClientHello (открыто) указывает hostname, чтобы сервер на одном IP выбрал правильный сертификат — виртуальный хостинг по TLS. ECH шифрует SNI для приватности.

В: Что такое ALPN и при чём тут HTTP/2? О: Согласование прикладного протокола в рамках TLS handshake (без лишнего RTT). Клиент шлёт список (h2, http/1.1), сервер выбирает. Так включается HTTP/2 на TLS.

В: Что делает InsecureSkipVerify и почему это опасно? О: Отключает проверку имени и цепочки сертификата → канал шифруется, но не аутентифицируется, открыт для MITM. Для самоподписанных надо вместо этого добавить CA в RootCAs.

В: Что такое mTLS и где применяется? О: Взаимная аутентификация: и сервер, и клиент предъявляют сертификаты. Сервер валидирует клиентский по своему набору CA (ClientAuth: RequireAndVerifyClientCert). Применяется в zero-trust, service mesh для service-to-service auth.

В: Почему 0-RTT данные нельзя использовать для любых запросов? О: Они уязвимы к replay (атакующий может переотправить захваченный 0-RTT пакет). Допустимо только для идемпотентных операций (GET); POST с побочными эффектами — нет.

В: Как ускорить TLS на высоконагруженном сервисе? О: Session resumption (session tickets/IDs) чтобы избегать полного handshake, OCSP stapling, ECDSA-сертификаты вместо RSA (дешевле подпись), TLS 1.3 (меньше RTT), AES-NI/аппаратное ускорение, переиспользование соединений (keep-alive), терминирование TLS на edge.

На что копают на senior+#

  • Анатомия 1-RTT в 1.3: как клиент угадывает группу для key_share и что происходит при HelloRetryRequest.
  • Session tickets vs session IDs, влияние на forward secrecy (ключ шифрования тикетов — единая точка компрометации, ротация STEK).
  • OCSP stapling, OCSP must-staple, почему CRL плохо масштабируется, CT (Certificate Transparency) логи.
  • ECH и угроза приватности от открытого SNI; как раньше работал domain fronting.
  • mTLS в service mesh: SPIFFE/SVID, ротация коротких сертификатов, как sidecar терминирует mTLS.
  • Производительность: ECDSA vs RSA cost, влияние record size на латентность, TLS False Start, 0-RTT anti-replay window.
  • Постквантовая криптография в TLS (гибридные key exchange, X25519+ML-KEM) — горячая тема 2024-2026.