Модуль: Сети и протоколы · Уровень: 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#
- Конфиденциальность — симметричное шифрование сессии (AES-GCM, ChaCha20-Poly1305).
- Целостность — AEAD (шифрование + аутентификация в одном).
- Аутентификация — проверка сертификата сервера (и опц. клиента) через 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.