Что такое процесс рукопожатия (handshake) в HTTPS?

Ответ

HTTPS Handshake (рукопожатие TLS/SSL) — это процесс установления безопасного соединения между клиентом (например, браузером) и сервером перед началом обмена зашифрованными данными. Его цель — аутентификация сервера (а иногда и клиента) и безопасная выработка общего секретного ключа для симметричного шифрования.

Основные этапы TLS 1.2 Handshake:

flowchart LR
    A[Клиент] <--> B[Сервер]
    subgraph Шаг 1: Приветствие и согласование
        A -- "Client Hello<br>Поддерживаемые шифры, версии TLS,<br>client_random" --> B
        B -- "Server Hello<br>Выбранный шифр, сертификат,<br>server_random" --> A
    end
    subgraph Шаг 2: Проверка и обмен ключами
        A -- "Проверяет сертификат<br>Генерирует pre_master_secret,<br>шифрует открытым ключом сервера" --> B
    end
    subgraph Шаг 3: Завершение и шифрование
        A -- "Change Cipher Spec, Finished" --> B
        B -- "Change Cipher Spec, Finished" --> A
        A <-- "Зашифрованное приложение<br>данные" --> B
    end
  1. Client Hello: Клиент отправляет случайное число (client_random), список поддерживаемых шифров и версий TLS.
  2. Server Hello: Сервер отвечает своим случайным числом (server_random), выбранным набором шифров и своим SSL-сертификатом, содержащим его открытый ключ.
  3. Проверка сертификата: Клиент проверяет сертификат (срок действия, подпись доверенным центром сертификации - CA, соответствие домену).
  4. (Client Key Exchange): Клиент генерирует pre_master_secret, шифрует его открытым ключом сервера из сертификата и отправляет.
  5. Выработка ключей: И клиент, и сервер независимо вычисляют master_secret из client_random, server_random и pre_master_secret, а затем на его основе генерируют одинаковые ключи для симметричного шифрования и MAC.
  6. Finished: Стороны обмениваются зашифрованными сообщениями Finished, подтверждая, что handshake прошел успешно и ключи совпадают.

Пример кода на C# (установка безопасного соединения):

using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

// Создание TcpClient и обертывание потока в SslStream
TcpClient client = new TcpClient("api.example.com", 443);
SslStream sslStream = new SslStream(client.GetStream(), false,
    new RemoteCertificateValidationCallback(ValidateServerCertificate), // Callback для проверки
    null);

try
{
    // Вызов AuthenticateAsClient инициирует TLS handshake
    sslStream.AuthenticateAsClient("api.example.com");
    // После успешного handshake можно писать/читать в sslStream
}
catch (AuthenticationException e)
{
    Console.WriteLine($"Ошибка аутентификации: {e.Message}");
}

// Callback для кастомной проверки сертификата (опционально)
private static bool ValidateServerCertificate(object sender, X509Certificate certificate,
    X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    if (sslPolicyErrors == SslPolicyErrors.None) return true;
    // Логика обработки ошибок (например, пропуск самоподписанных сертификатов для dev)
    return false; // В продакшене всегда возвращать false при ошибках
}

Эволюция и оптимизации:

  • TLS 1.3: Значительно ускорен handshake, часто до 1 RTT (один обмен). Удалены небезопасные алгоритмы шифрования.
  • Session Resumption (TLS Session Tickets): Позволяет повторно использовать параметры предыдущей сессии для быстрого восстановления соединения без полного handshake.
  • False Start: Клиент может начать отправлять зашифрованные данные до получения подтверждения Finished от сервера, уменьшая задержку.

Критически важные аспекты для разработчика:

  1. Сертификаты: Всегда используйте валидные сертификаты от доверенных CA в продакшене. Самоподписанные сертификаты — только для разработки и тестирования.
  2. Алгоритмы: Настройте сервер на использование современных, безопасных шифров (отключите SSLv3, TLS 1.0/1.1, слабые алгоритмы).
  3. HTTP Strict Transport Security (HSTS): Заголовок, принудительно указывающий браузеру использовать только HTTPS для данного домена.

Ответ 18+ 🔞

Смотри, вот тебе про HTTPS рукопожатие, но без этих заумных учебников, а как есть на самом деле.

Представь, ты заходишь на сайт, а там вместо «http» — «https». Это типа как прийти в бар и сказать: «Мне пиво, но так, чтобы никто не подслушал, не подменил и вообще был уверен, что ты — настоящий бармен, а не левый мужик в фартуке».

Вот это самое TLS/SSL handshake — это как раз такая процедура «опознания» и договорённости, как шифроваться будем.


Как это работает, если по-простому:

  1. Клиент (браузер) говорит серверу:
    — «Привет, я вот такие шифры понимаю, вот моя случайная строка (client_random), давай общаться по TLS 1.2 или 1.3».
    Это типа Client Hello.

  2. Сервер отвечает:
    — «Ок, давай вот этот шифр, вот моя случайная строка (server_random), и вот мой сертификат — там мой публичный ключ и подпись центра сертификации, чтобы ты проверил, что я не левый».
    Это Server Hello.

  3. Клиент проверяет сертификат:
    — Срок действия не вышел?
    — Центр сертификации известный?
    — Домен в сертификате совпадает с тем, куда я обращаюсь?
    Если что-то не так — браузер ругается красной страницей «Ваше соединение не защищено», и правильно делает, блядь.

  4. Клиент генерирует pre_master_secret, шифрует его публичным ключом сервера (из сертификата) и шлёт обратно.
    Расшифровать это может только сервер своим приватным ключом — так что даже если кто-то перехватит, нихуя не прочитает.

  5. Обе стороны из client_random, server_random и pre_master_secret вычисляют одинаковый master_secret, а из него уже генерируют ключи для шифрования трафика.
    Всё, теперь у них есть общий секрет, и они могут болтать зашифровано.

  6. Финишные сообщения — они проверяют, что ключи совпали и handshake прошёл без косяков.
    После этого начинается нормальная работа: запросы-ответы, но уже зашифрованные.


Если накидать код на C# (примерно так это выглядит в реальности):

using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

TcpClient client = new TcpClient("api.example.com", 443);
SslStream sslStream = new SslStream(client.GetStream(), false,
    new RemoteCertificateValidationCallback(ValidateServerCertificate),
    null);

try
{
    // Вот эта строчка и запускает весь тот трёп с рукопожатием
    sslStream.AuthenticateAsClient("api.example.com");
    // Если не вылетело исключение — значит, соединение установлено, можно общаться
}
catch (AuthenticationException e)
{
    Console.WriteLine($"Короче, аутентификация не прокатила: {e.Message}");
}

// А это callback, где можно свою логику проверки сертификата впилить
private static bool ValidateServerCertificate(object sender, X509Certificate certificate,
    X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    // Если ошибок нет — ок
    if (sslPolicyErrors == SslPolicyErrors.None) return true;

    // В продакшене тут надо жёстко проверять, а для теста иногда пропускаем самоподписанные
    // Но вообще так делать — это на свой страх и риск, конечно
    return false;
}

Что ещё важно знать:

  • TLS 1.3 пришёл и сделал handshake быстрее — иногда за один обмен пакетами (1 RTT). Убрали кучу старых, небезопасных алгоритмов, упростили всё.
  • Session Resumption — если ты уже общался с сервером, можно восстановить сессию быстрее, без полного рукопожатия. Как будто тебя в баре уже узнали в лицо.
  • False Start — клиент может начать слать данные ещё до окончания handshake, чтобы не ждать. Рискованно, но если настроено правильно — работает.

Что часто ебёт разработчиков:

  1. Сертификаты — в продакшене обязательно от доверенного центра (Let's Encrypt, DigiCert и т.д.). Самоподписанные — только для локалки и тестов, иначе браузеры будут материться.
  2. Алгоритмы — на сервере надо отключать древнее говно: SSLv3, TLS 1.0, слабые шифры. Иначе безопасность — как решето.
  3. HSTS (HTTP Strict Transport Security) — это такой заголовок, который говорит браузеру: «Запоминай, на этот домен только через HTTPS, даже если пользователь ввел http». Чтобы не было downgrade-атак.

Короче, HTTPS handshake — это не магия, а чёткий протокол, который гарантирует, что тебя не прослушивают и не подменяют данные. Если делаешь что-то с безопасностью — не хуярь костыли, а читай доки и настраивай правильно. Иначе потом будет «ой, а нас взломали», а виноват окажешься ты.