Как происходит обмен сертификатами в HTTPS
Что проверяют
Понимаете ли вы, что сертификат в TLS нужен для аутентификации сервера, а не для шифрования данных, и знаете ли, как выглядит рукопожатие TLS 1.3. Следом для Go почти всегда спрашивают, как настроить tls.Config для mTLS и почему InsecureSkipVerify: true нельзя оставлять в проде.
Как отвечать
Опишите рукопожатие TLS 1.3, оно укладывается в один круг обмена:
- ClientHello: версии, наборы шифров, имя сервера в SNI и сразу
key_share, открытая часть эфемерного ключа ECDHE (обычно X25519, в свежих версиях Go по умолчанию ещё и гибридный постквантовый X25519MLKEM768); - ServerHello: сервер выбирает параметры и отдаёт свою часть ключа. С этого момента обе стороны вычисляют общий секрет, и всё дальнейшее уже зашифровано;
- Certificate: сервер присылает листовой сертификат и промежуточные, корневой не нужен, он уже есть у клиента;
- CertificateVerify: подпись всей переписки закрытым ключом сервера. Так сервер доказывает, что владеет ключом от сертификата;
- Finished: обе стороны подтверждают, что видели одну и ту же переписку.
Клиент при этом проверяет цепочку до доверенного корня, срок действия и совпадение имени с полем SAN, поле CN Go давно для этого не использует. При mTLS сервер добавляет CertificateRequest, и клиент отвечает своим сертификатом и CertificateVerify.
В Go это crypto/tls: у сервера Certificates, ClientAuth: tls.RequireAndVerifyClientCert и ClientCAs, у клиента RootCAs из x509.NewCertPool() и ServerName. MinVersion по умолчанию уже TLS 1.2, для внутренних сервисов разумно поднять до tls.VersionTLS13. Автоматические сертификаты Let's Encrypt даёт пакет golang.org/x/crypto/acme/autocert.
Где спотыкаются
Рассказывают, что клиент шифрует сессионный ключ открытым ключом сервера. Это обмен RSA из TLS 1.2 без прямой секретности, в TLS 1.3 его убрали, ключ вырабатывается через ECDHE.
Ставят InsecureSkipVerify: true, чтобы «заработало» с самоподписанным сертификатом. Правильно добавить свой CA в RootCAs.
Отдают с сервера только листовой сертификат без промежуточных. Браузер иногда достроит цепочку сам, а Go-клиент упадёт с x509: certificate signed by unknown authority.