Как работает HTTPS
HTTPS (Hypertext Transfer Protocol Secure) — это расширение протокола передачи гипертекста (HTTP). HTTPS передаёт зашифрованные данные с использованием протокола TLS (Transport Layer Security). Если данные будут перехвачены в сети, всё, что получит злоумышленник, — это бинарный код.
Пояснение к диаграмме (этапы соединения)
#1. TCP Handshake (Рукопожатие TCP)
Клиент и сервер устанавливают соединение через три этапа: SYN, SYN + ACK и ACK - известные как трёхстороннее рукопожатие (Three-Way Handshake).
▷ TCP SYN
Synchronize — Клиент посылает серверу начальный номер последовательности (например, Sequence Number = 1000
). Это значение сообщает серверу, с какого номера будут начинаться байты данных от клиента.
◁ TCP SYN + ACK
Synchronize + Acknowledge — Сервер отвечает своим собственным начальным номером последовательности (например, Sequence Number = 3000
) и подтверждает, что получил начальный номер клиента с помощью номера подтверждения Acknowledgment Number = 1001
(номер последовательности клиента + 1).
▷ TCP ACK
Acknowledge — Клиент подтверждает получение начального номера последовательности сервера, отправляя Acknowledgment Number = 3001
(номер последовательности сервера + 1).
Теперь клиент и сервер могут начать обмен данными. Таким образом, каждый из участников знает, с какого номера будут начинаться данные, и может следить за их последовательностью и целостностью.
Номер последовательности (Sequence Number) — это уникальный идентификатор, используемый в протоколе TCP для отслеживания каждого байта данных, передаваемых между клиентом и сервером. Он обеспечивает упорядоченную передачу данных и помогает избежать дублирования или потери пакетов.
#2. Certificate Check (Проверка сертификата)
Клиент и сервер обмениваются сообщениями для проверки подлинности и установления доверия на основе сертификата сервера.
- Клиент отправляет сообщение Client Hello.
- Сервер отвечает Server Hello и отправляет сертификат, подтверждающий его подлинность.
- Клиент проверяет сертификат и принимает решение о продолжении соединения.
▷ Client Hello
Клиент отправляет серверу сообщение Client Hello
, в котором указывает:
- Поддерживаемую версию протокола TLS.
- Список предпочитаемых алгоритмов шифрования.
- Случайное число (random nonce).
Это сообщение инициирует начало процесса проверки подлинности.
◁ Server Hello
Сервер отвечает сообщением Server Hello
, выбирая параметры, которые будут использоваться для соединения. Он также генерирует свое случайное число и отправляет его клиенту для дальнейшего использования - создания сессионных ключей.
◁ Certificate (public key)
Сервер отправляет клиенту свой сертификат, который включает публичный ключ, информацию о центре сертификации (CA), срок действия и другие параметры. Сертификат подписан доверенным CA, чтобы клиент мог проверить его подлинность.
◁ Server Hello Done
Сервер завершает этап проверки сертификата, отправляя сообщение Server Hello Done
, которое сигнализирует клиенту о завершении передачи всех необходимых данных для проверки.
Проверка сертификата — это процесс, при котором клиент проверяет подлинность сертификата сервера, включая подпись CA, срок действия, соответствие доменного имени и проверку отзыва сертификата.
#3. Key Exchange (Обмен ключами)
Клиент и сервер обмениваются сессионным ключом для дальнейшего шифрования данных.
- Клиент генерирует сессионный ключ (Session Key) и шифрует его с помощью публичного ключа (Public Key) сервера.
- Зашифрованный сессионный ключ передается на сервер.
- Оба участника устанавливают параметры шифрования, используя "Change Cipher Spec" и завершают настройку с помощью сообщения Finished.
▷ Client Key Exchange
Клиент создает сессионный ключ, шифрует его с помощью публичного ключа сервера, полученного из сертификата, и отправляет зашифрованный ключ на сервер.
▷ Change Cipher Spec
Клиент уведомляет сервер о том, что он будет использовать новые параметры шифрования (сессионный ключ) для дальнейших сообщений, отправляя сообщение Change Cipher Spec
.
▷ Finished
Клиент завершает настройку, отправляя сообщение Finished
, зашифрованное новым сессионным ключом, чтобы подтвердить успешное завершение обмена ключами.
◁ Change Cipher Spec
Сервер принимает сессионный ключ, отправленный клиентом, и отвечает сообщением Change Cipher Spec
, указывая, что он также будет использовать этот ключ для шифрования данных.
◁ Finished
Сервер завершает процесс обмена ключами, отправляя сообщение Finished
, зашифрованное сессионным ключом, чтобы подтвердить успешное завершение настройки.
Сессионный ключ (Session Key) — это временный ключ, используемый для шифрования данных во время сеанса связи. Его используют для симметричного шифрования, так как это быстрее и эффективнее по сравнению с асимметричным шифрованием.
#4. Data Transmission (Передача данных)
После успешного обмена ключами клиент и сервер используют симметричное шифрование для безопасной передачи данных, используя сессионный ключ.
▷ Encrypted Data (session key)
Клиент шифрует все передаваемые данные с помощью сессионного ключа и отправляет их на сервер.
◁ Encrypted Data (session key)
Сервер получает зашифрованные данные, расшифровывает их с помощью того же сессионного ключа и отправляет обратно зашифрованный ответ.
Симметричное шифрование используется для всех последующих обменов данными после установления соединения, что обеспечивает высокую производительность и безопасность при передаче информации.
Заметки
HTTPS используют оба типа шифрования
-
Ассиметричное шифрование (asymmetric encryption) используется на этапе обмена ключами. Это необходимо для безопасной передачи сессионного ключа. Ассиметричное шифрование использует публичный и приватный ключи.
- Симметричное шифрование (symmetric encryption) используется для передачи данных после установления соединения. Оба участника используют одинаковый сессионный ключ для шифрования и дешифрования данных.
Таким образом, в HTTPS ассиметричное шифрование применяется только на начальном этапе, а затем для основной передачи данных используется симметричное шифрование.
Случайное число (random nonce)
Случайное число (random nonce) — это уникальное, случайно сгенерированное число или строка, используемая один раз в криптографических протоколах для обеспечения безопасности. Оно предотвращает атаки воспроизведения (replay attacks) и помогает установить уникальные параметры для каждой новой сессии.
В контексте TLS и SSL, случайное число используется при рукопожатии (handshake) следующим образом:
- Client Hello: Клиент генерирует свое случайное число (Client Random) и отправляет его серверу.
- Server Hello: Сервер генерирует свое случайное число (Server Random) и отправляет его клиенту.
Эти случайные числа используются для:
- Создания сессионных ключей: Клиент и сервер комбинируют свои случайные числа с предварительным ключом (pre-master secret) для генерации сессионного ключа, который будет использоваться для симметричного шифрования.
- Обеспечения уникальности: Каждая сессия имеет уникальные параметры, что предотвращает использование повторных сообщений и защищает от атак повторного воспроизведения.
Иными словами, случайное число гарантирует, что каждое новое соединение между клиентом и сервером будет уникальным и безопасным, даже если оно происходит между одними и теми же сторонами.
Как создается сессионный ключ
Создание сессионного ключа зависит от конкретного метода обмена ключами, который используется в протоколе TLS. Рассмотрим основные варианты: RSA и ECDHE.
RSA: Создание сессионного ключа с использованием RSA (TLS 1.2 и ниже)
При использовании алгоритма RSA, клиент самостоятельно генерирует сессионный ключ следующим образом:
-
Генерация Pre-Master Secret:
Клиент создает случайное число (Pre-Master Secret), которое будет использоваться в процессе создания сессионного ключа. -
Шифрование с помощью публичного ключа:
Клиент шифрует Pre-Master Secret с помощью публичного ключа, полученного из сертификата сервера. -
Отправка на сервер:
Зашифрованное значение Pre-Master Secret отправляется на сервер в сообщении Client Key Exchange. -
Создание Master Secret:
Клиент и сервер используют свои случайные числа (Client Random и Server Random) вместе с Pre-Master Secret для создания Master Secret. - Генерация сессионного ключа:
На основе Master Secret обе стороны (клиент и сервер) создают одинаковые сессионные ключи (Session Keys) для симметричного шифрования. Этот процесс выполняется с помощью функции псевдослучайных чисел (PRF), которая гарантирует уникальность ключей.
Итог: Клиент генерирует Pre-Master Secret, который служит основой для создания сессионного ключа.
ECDHE: Создание сессионного ключа с использованием ECDHE (TLS 1.2 и TLS 1.3)
Алгоритм ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) используется для создания сессионного ключа на основе метода Диффи-Хеллмана с использованием эллиптических кривых. Это обеспечивает прямую секретность (PFS).
-
Генерация пары ключей:
Клиент генерирует свою пару ключей: приватный ключ (Private Key) и публичный ключ (Public Key) на основе эллиптической кривой. -
Отправка публичного ключа:
Клиент отправляет свой публичный ключ серверу в сообщении Client Key Exchange. -
Генерация общего секрета:
Клиент и сервер, используя свои приватные ключи и публичный ключ друг друга, вычисляют общий секрет (Shared Secret) с помощью алгоритма ECDHE. -
Создание Master Secret:
Общий секрет (Shared Secret), вместе с случайными числами (Client Random и Server Random), используется для создания Master Secret. - Генерация сессионного ключа:
На основе Master Secret клиент и сервер генерируют сессионные ключи для симметричного шифрования данных.
Итог: Сессионный ключ создается на основе общего секрета, который высчитывается обеими сторонами на основе их приватных и публичных ключей.
Различия между RSA и ECDHE
-
RSA: Клиент генерирует Pre-Master Secret и передает его зашифрованным на сервер, который затем использует его для создания сессионного ключа.
- ECDHE: Клиент и сервер совместно создают общий секрет (Shared Secret) на основе приватных и публичных ключей. Этот общий секрет используется для создания сессионного ключа.
Таким образом, при использовании ECDHE процесс создания сессионного ключа более безопасен, так как даже если приватный ключ сервера будет скомпрометирован в будущем, это не повлияет на безопасность прошлых сеансов (прямая секретность).
Пример запроса через curl
Давайте теперь, в качестве реального примера, сделаем HTTPS зарос на google.com с помощью curl, который выдаст нам подробную информацию о ходе запроса:
$ curl -v https://google.com
Получим:
* Trying 173.194.221.138:443... * Connected to google.com (173.194.221.138) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs * TLSv1.0 (OUT), TLS header, Certificate Status (22): * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS header, Certificate Status (22): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS header, Finished (20): * TLSv1.2 (IN), TLS header, Supplemental data (23): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.2 (OUT), TLS header, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS header, Supplemental data (23): * TLSv1.3 (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 * ALPN, server accepted to use h2 * Server certificate: * subject: CN=*.google.com * start date: Aug 26 06:33:47 2024 GMT * expire date: Nov 18 06:33:46 2024 GMT * subjectAltName: host "google.com" matched cert's "google.com" * issuer: C=US; O=Google Trust Services; CN=WR2 * SSL certificate verify ok. * Using HTTP2, server supports multiplexing * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * TLSv1.2 (OUT), TLS header, Supplemental data (23): * TLSv1.2 (OUT), TLS header, Supplemental data (23): * TLSv1.2 (OUT), TLS header, Supplemental data (23): * Using Stream ID: 1 (easy handle 0x6387721e8eb0) * TLSv1.2 (OUT), TLS header, Supplemental data (23): > GET / HTTP/2 > Host: google.com > user-agent: curl/7.81.0 > accept: */* > * TLSv1.2 (IN), TLS header, Supplemental data (23): * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * old SSL session ID is stale, removing * TLSv1.2 (IN), TLS header, Supplemental data (23): * TLSv1.2 (OUT), TLS header, Supplemental data (23): * TLSv1.2 (IN), TLS header, Supplemental data (23): * TLSv1.2 (IN), TLS header, Supplemental data (23): < HTTP/2 301 < location: https://www.google.com/ < content-type: text/html; charset=UTF-8 < content-security-policy-report-only: object-src 'none';base-uri 'self' < date: Sun, 29 Sep 2024 21:01:56 GMT < expires: Tue, 29 Oct 2024 21:01:56 GMT < cache-control: public, max-age=2592000 < server: gws < content-length: 220 < x-xss-protection: 0 < x-frame-options: SAMEORIGIN < alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 < * TLSv1.2 (IN), TLS header, Supplemental data (23): <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8"> <TITLE>301 Moved</TITLE></HEAD><BODY> <H1>301 Moved</H1> The document has moved <A HREF="https://www.google.com/">here</A>. </BODY></HTML> * TLSv1.2 (IN), TLS header, Supplemental data (23): * Connection #0 to host google.com left intact