Що таке TLS/SSL і навіщо це потрібно?
Основні поняття. SSL та TLS
SSL (Secure Sockets Layer) та TLS (Transport Layer Security) — це криптографічні протоколи, що забезпечують захищену передачу даних через мережі, такі як Інтернет. Хоча SSL є попередником TLS, терміни часто використовуються взаємозамінно. Останньою версією є TLS 1.3, яка приносить покращення в безпеці та швидкості.
Мета та завдання SSL/TLS
Протоколи SSL/TLS вирішують три основні завдання:
Конфіденційність: Шифрування даних гарантує, що сторонні особи не зможуть їх прочитати під час передачі.
Автентифікація: Підтвердження особи сервера (і, при необхідності, клієнта) через цифрові сертифікати.
Цілісність: Гарантія того, що дані не були змінені або підроблені під час передачі.
Важливість захищеного з'єднання у сучасних додатках
З ростом кількості кібератак та підслуховування мережевого трафіку, використання захищених з'єднань стало обов'язковим стандартом. Без TLS/SSL ваші додатки та користувачі піддаються ризику крадіжки даних, компрометації облікових записів та інших загроз.
PKI (Public Key Infrastructure)
Що таке PKI і навіщо воно потрібне?
PKI (Інфраструктура відкритих ключів) — це система, яка керує створенням, розповсюдженням, зберіганням та відкликанням цифрових сертифікатів та відкритих ключів. PKI дозволяє організаціям та користувачам безпечно обмінюватися інформацією через мережі, використовуючи криптографію відкритого ключа.
Компоненти PKI
Сертифікаційний центр (CA): Довірена організація або система, яка видає цифрові сертифікати. CA підтверджує особу суб'єкта і підписує сертифікат своїм приватним ключем.
Кореневі сертифікати (Root Certificates): Сертифікати верхнього рівня, які самопідписані CA. Вони є основою довіри у PKI. Кореневі сертифікати зберігаються в операційних системах та браузерах як довірені.
Проміжні сертифікати (Intermediate Certificates): Сертифікати, видані кореневим CA, які самі можуть видавати інші сертифікати. Вони створюють ієрархію довіри та дозволяють кореневому CA делегувати відповідальність.
Кінцеві сертифікати (End-Entity Certificates): Сертифікати, видані для кінцевих суб'єктів — серверів або користувачів. Вони використовуються безпосередньо для встановлення захищених з'єднань.
Ланцюжок сертифікатів (Chain of Trust)
Що таке ланцюжок довіри?
Ланцюжок довіри — це послідовність сертифікатів, де кожен сертифікат підписаний наступним у ланцюжку, починаючи від кінцевого сертифіката до кореневого сертифіката CA. Цей ланцюжок дозволяє клієнту перевірити, що сертифікат сервера був виданий довіреною організацією.
Як працює верифікація сертифікатів?
Коли клієнт отримує сертифікат сервера, він:
Перевіряє підпис сертифіката за допомогою відкритого ключа проміжного CA.
Повторює процес для проміжного сертифіката, використовуючи відкритий ключ наступного CA у ланцюжку.
Продовжує, поки не дійде до кореневого сертифіката, якому довіряє (зберігається у його сховищі довірених сертифікатів).
Чому використовуються проміжні сертифікати?
Використання проміжних сертифікатів:
Безпека: Кореневі CA захищають свої приватні ключі, мінімізуючи ризик компрометації.
Масштабування: Делегування дозволяє ефективніше керувати видачею сертифікатів.
Контроль: Проміжні CA можуть спеціалізуватися на різних типах сертифікатів або політиках безпеки.
TLS-з'єднання. Детальний огляд процесу
Процес встановлення TLS-з'єднання (Handshake)
Встановлення TLS-з'єднання відбувається через серію обмінів між клієнтом та сервером. Для кращого розуміння, давайте розглянемо детально кожен крок, включаючи приклади повідомлень, як вони можуть бути побачені в мережевому сніфері, наприклад, Wireshark.
Крок 1: ClientHello
Клієнт ініціює з'єднання, відправляючи повідомлення ClientHello, яке містить:
Версію протоколу TLS, яку підтримує клієнт (наприклад, TLS 1.2 або TLS 1.3).
Список підтримуваних шифрів (Cipher Suites), включаючи ECDHE-шифри.
Список підтримуваних компресійних методів.
Випадкове число (Client Random).
Розширення (Extensions), такі як SNI (Server Name Indication) та підтримувані групи (Supported Groups) для ECDHE.
Приклад повідомлення (з Wireshark):
TLSv1.2 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: ...
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: ...
Version: TLS 1.2 (0x0303)
Random: <Client Random>
Session ID Length: 0
Cipher Suites Length: ...
Cipher Suites (list of cipher suites)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xC030)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xC02F)
...
Compression Methods Length: 1
Compression Methods (1 method)
Compression Method: null (0)
Extensions Length: ...
Extension: supported_groups
Supported Groups Length: ...
Supported Groups (list of groups)
Named Group: x25519 (0x001d)
Named Group: secp256r1 (0x0017)
...
Extension: ec_point_formats
...
Extension: server_name
Server Name Indication extension
Server Name: example.com
...
Крок 2: ServerHello
Сервер відповідає повідомленням ServerHello, де:
Підтверджує версію протоколу TLS.
Вибирає шифр (Cipher Suite) з тих, що запропонував клієнт (наприклад, ECDHE-шифр).
Відправляє своє випадкове число (Server Random).
Вказує вибрані розширення та параметри.
Приклад повідомлення:
TLSv1.2 Record Layer: Handshake Protocol: Server Hello
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: ...
Handshake Protocol: Server Hello
Handshake Type: Server Hello (2)
Length: ...
Version: TLS 1.2 (0x0303)
Random: <Server Random>
Session ID Length: ...
Session ID: ...
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xC030)
Compression Method: null (0)
Extensions Length: ...
Extension: ec_point_formats
...
Extension: session_ticket
...
...
Крок 3: Сервер відправляє сертифікат
Сервер відправляє своє повідомлення Certificate, яке містить:
Сертифікат сервера (та, за потреби, ланцюжок проміжних сертифікатів).
Цей сертифікат містить відкритий ключ сервера, який використовується для цифрового підпису.
Приклад повідомлення:
TLSv1.2 Record Layer: Handshake Protocol: Certificate
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: ...
Handshake Protocol: Certificate
Handshake Type: Certificate (11)
Length: ...
Certificates Length: ...
Certificates (chain of certificates)
Certificate Length: ...
Certificate: <Сертифікат сервера>
Certificate Length: ...
Certificate: <Проміжний сертифікат>
...
Крок 4: Server Key Exchange
При використанні ECDHE сервер відправляє повідомлення Server Key Exchange, яке містить:
Параметри еліптичної кривої, які будуть використовуватися для обміну ключами.
Публічний ключ сервера для ECDHE.
Цифровий підпис цих параметрів, підписаний приватним ключем сервера (з сертифіката), для підтвердження автентичності.
TLSv1.2 Record Layer: Handshake Protocol: Server Key Exchange
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: ...
Handshake Protocol: Server Key Exchange
Handshake Type: Server Key Exchange (12)
Length: ...
EC Diffie-Hellman Server Params
Curve Type: named_curve (0x03)
Named Curve: secp256r1 (0x0017)
Public Key Length: 65
Public Key: <Публічний ключ сервера>
Signature Algorithm: rsa_sha256 (0x0401)
Signature Length: ...
Signature: <Цифровий підпис>
Крок 5: ServerHelloDone
Сервер відправляє повідомлення ServerHelloDone, сигналізуючи, що його частина рукостискання завершена.
TLSv1.2 Record Layer: Handshake Protocol: Server Hello Done
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 4
Handshake Protocol: Server Hello Done
Handshake Type: Server Hello Done (14)
Length: 0
Крок 6: Перевірка сертифіката клієнтом
Клієнт перевіряє сертифікат сервера:
Переконується, що сертифікат дійсний (термін дії, підписаний довіреним CA).
Перевіряє відповідність доменного імені.
Перевіряє цифровий підпис у Server Key Exchange для підтвердження автентичності параметрів ECDHE.
Крок 7: Client Key Exchange
Клієнт відправляє повідомлення Client Key Exchange, яке містить:
Публічний ключ клієнта для ECDHE.
TLSv1.2 Record Layer: Handshake Protocol: Client Key Exchange
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: ...
Handshake Protocol: Client Key Exchange
Handshake Type: Client Key Exchange (16)
Length: ...
EC Diffie-Hellman Client Params
Public Key Length: 65
Public Key: <Публічний ключ клієнта>
Крок 8: Зміна Cipher Spec та завершення рукостискання
Обидві сторони обчислюють спільний секрет (Pre-Master Secret) на основі обміну публічними ключами ECDHE.
Після цього клієнт відправляє повідомлення Change Cipher Spec, сигналізуючи про перехід на шифроване з'єднання.
Далі клієнт відправляє повідомлення Finished, яке містить перевірочний хеш усіх попередніх повідомлень, зашифрований новим симетричним ключем.
Сервер відповідає аналогічними повідомленнями Change Cipher Spec та Finished.
TLSv1.2 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
Content Type: Change Cipher Spec (20)
Version: TLS 1.2 (0x0303)
Length: 1
Change Cipher Spec Message
TLSv1.2 Record Layer: Handshake Protocol: Encrypted Handshake Message
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: ...
Handshake Protocol: Encrypted Handshake Message
[Encrypted handshake message]
Крок 9: Шифрований трафік
Після успішного рукостискання подальший трафік між клієнтом та сервером шифрується за допомогою симетричного алгоритму та сесійного ключа, отриманого з Pre-Master Secret.
Взаємодія шифрування та сертифікатів
Сертифікати використовуються для автентифікації сервера та підпису параметрів обміну ключами.
Асиметричне шифрування використовується для цифрових підписів (RSA або ECDSA) параметрів ECDHE.
Алгоритм Деффі-Хеллмана на еліптичних кривих (ECDHE) використовується для безпечного обміну ключами та забезпечення пріоритету перед конфіденційністю (Forward Secrecy).
Симетричне шифрування використовується для шифрування основного трафіку після рукостискання.
Хеш-функції забезпечують цілісність даних.
Практичний приклад: Створення самопідписаного сертифіката
Створення самопідписаного сертифіката може бути корисним для тестування або внутрішніх потреб.
Генерація приватного ключа за допомогою OpenSSL
Спочатку потрібно згенерувати приватний ключ:
openssl genrsa -out private.key 2048
Ця команда створює приватний RSA ключ довжиною 2048 біт.
Створення самопідписаного сертифіката
Далі створюємо сертифікат на основі приватного ключа:
openssl req -x509 -new -nodes -key private.key -sha256 -days 365 -out certificate.crt
-x509: Вказує, що потрібно створити самопідписаний сертифікат.
-new: Створює новий сертифікат.
-nodes: Не шифрувати приватний ключ.
-days 365: Термін дії сертифіката.
Під час виконання команди вас попросять ввести інформацію для сертифіката (країна, організація, CN тощо).
Використання сертифіката у локальному середовищі (наприклад, nginx)
Після створення сертифіката можна налаштувати веб-сервер для використання HTTPS:
server {
listen 443 ssl;
server_name example.local;
ssl_certificate /path/to/certificate.crt;
ssl_certificate_key /path/to/private.key;
location / {
root /var/www/html;
index index.html;
}
}
Після перезапуску nginx ваш сервер буде доступний по HTTPS. Проте браузер може попереджати про недовірений сертифікат, оскільки він самопідписаний.
PKI і TLS/SSL у Java
У Java є вбудовані інструменти та API для роботи з TLS/SSL та PKI.
Вбудовані інструменти Java для роботи з PKI
Keystore: Файл, що зберігає приватні ключі та відповідні сертифікати. Використовується для автентифікації сервера або клієнта.
Truststore: Файл, що зберігає сертифікати довірених CA. Використовується для верифікації сертифікатів інших сторін.
Keytool. Управління ключами та сертифікатами
keytool — це утиліта Java для роботи з keystore та truststore.
Створення keystore з парою ключів:
keytool -genkeypair -alias mykey -keyalg RSA -keysize 2048 -keystore keystore.jks -validity 365
Параметри:
-alias: Ім'я ключа.
-keyalg: Алгоритм ключа (RSA).
-keystore: Файл сховища ключів.
Перегляд вмісту keystore:
keytool -list -v -keystore keystore.jks
Імпорт сертифіката до truststore:
keytool -import -alias mycert -file certificate.crt -keystore truststore.jks
SSLContext. Створення SSL-з'єднань у Java
SSLContext — це клас, який представляє контекст SSL, включаючи конфігурацію ключів та менеджерів довіри.
Приклад створення SSLContext:
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream("keystore.jks"), "keystorePassword".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, "keyPassword".toCharArray());
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream("truststore.jks"), "truststorePassword".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
Truststore та cacerts у Java. Як це працює?
Java поставляється з власним truststore — файлом cacerts, який містить кореневі сертифікати відомих CA. Він знаходиться в директорії lib/security
вашої встановленої Java.
При необхідності ви можете:
Додати сертифікат до cacerts: Хоча це не рекомендується, оскільки при оновленні Java ваші зміни можуть бути втрачені.
Використовувати власний truststore: Більш безпечний та контрольований підхід.
Де можуть виникнути проблеми з TLS/SSL у Java?
Типові проблеми, з якими стикаються Java-розробники
SSLHandshakeException
Ця помилка виникає під час встановлення TLS-з'єднання і може бути спричинена:
Недовірений сертифікат: Сертифікат сервера не довірений клієнтом.
Невідповідність протоколів: Клієнт і сервер не підтримують спільну версію TLS або набір шифрів.
Закінчився термін дії сертифіката: Сертифікат більше не дійсний.
Неправильна конфігурація SSLContext
Неправильне налаштування менеджерів ключів або довіри може призвести до помилок під час встановлення з'єднання.
Використання застарілих версій TLS
Деякі системи можуть вимагати використання новіших версій TLS (1.2 або 1.3), тоді як ваш додаток намагається використовувати старі версії.
Причини та рішення для кожної проблеми
Недовірений сертифікат:
Причина: Сертифікат сервера не присутній у truststore клієнта.
Рішення: Додайте необхідні сертифікати до truststore.
Невідповідність протоколів:
Причина: Відсутність спільних протоколів або шифрів.
Рішення: Налаштуйте підтримку потрібних версій TLS та шифрів у вашому додатку.
Закінчився термін дії сертифіката:
Причина: Сертифікат є недійсним через закінчення терміну.
Рішення: Оновіть сертифікат на сервері та в truststore.
Як дебажити та вирішувати проблеми з TLS/SSL у Java?
Увімкнення детального логування
Додавши параметр JVM, можна отримати детальні логи TLS-з'єднань:
-Djavax.net.debug=ssl,handshake,failure
Це дозволить побачити кроки встановлення з'єднання та можливі місця помилок.
Перевірка ланцюжка сертифікатів через OpenSSL
Використовуйте OpenSSL для діагностики:
openssl s_client -connect example.com:443 -showcerts
Це покаже ланцюжок сертифікатів, які надає сервер, та можливі проблеми.
Оновлення truststore для додавання нових сертифікатів
Якщо сертифікат сервера не довірений, його потрібно додати до truststore:
keytool -import -alias servercert -file server.crt -keystore truststore.jks
Виправлення помилок із налаштуванням SSLContext
Переконайтеся, що SSLContext ініціалізований правильно, з коректними менеджерами ключів та довіри. Перевірте, чи файли keystore та truststore доступні та містять необхідні ключі та сертифікати.
Рекомендації для вирішення проблем з PKI і TLS/SSL у Java
Регулярно оновлюйте сертифікати: Слідкуйте за термінами дії сертифікатів та оновлюйте їх заздалегідь.
Використовуйте сучасні версії TLS: Налаштуйте ваші додатки на підтримку TLS 1.2 та 1.3, відмовившись від застарілих версій.
Тестуйте у різних середовищах: Перевіряйте роботу вашого додатку у тестових та stage середовищах, щоб виявити можливі проблеми.
Використовуйте інструменти аналізу: Наприклад, Qualys SSL Labs дозволяє проаналізувати налаштування вашого сервера та виявити вразливості.
Документуйте налаштування: Ведіть документацію щодо конфігурації TLS/SSL у вашому проєкті, щоб полегшити підтримку та оновлення.
Висновки
Розуміння та правильне налаштування TLS/SSL та PKI є критично важливими для забезпечення безпеки ваших додатків. Глибоке знання того, як працюють цифрові сертифікати, ланцюжки довіри та процес встановлення захищеного з'єднання, дозволить вам уникнути багатьох поширених проблем та забезпечити надійний захист даних ваших користувачів.
Пам'ятайте, що безпека — це постійний процес. Регулярно оновлюйте свої знання, слідкуйте за новими стандартами та найкращими практиками у сфері кібербезпеки. Це не лише захистить ваші додатки, але й зміцнить довіру користувачів до ваших продуктів.
Детальний аналіз TLS-з'єднання з використанням Wireshark
Для того щоб краще зрозуміти, як відбувається обмін повідомленнями під час встановлення TLS-з'єднання, можна скористатися мережевим аналізатором Wireshark. Давайте розглянемо приклад захоплення трафіку між клієнтом та сервером.
Захоплення трафіку за допомогою Wireshark
Запустіть Wireshark та виберіть інтерфейс мережі, який використовується для підключення до Інтернету.
Фільтруйте трафік за допомогою фільтра
tcp.port == 443
, щоб бачити лише HTTPS-з'єднання.Відвідайте захищений сайт (наприклад, https://www.example.com) у браузері.
Зупиніть захоплення після завантаження сторінки.
Аналіз повідомлень
ClientHello
У Wireshark знайдіть перше повідомлення з описом Client Hello.
Frame: Номер кадру.
Source: IP-адреса клієнта.
Destination: IP-адреса сервера.
Info:
Client Hello
.
Приклад:
Frame 5: 528 bytes on wire
Source: 192.168.1.100 (192.168.1.100)
Destination: 93.184.216.34 (93.184.216.34)
TLSv1.2 Record Layer: Handshake Protocol: Client Hello
ServerHello та серверний сертифікат
Знайдіть відповідь сервера з Server Hello та Certificate.
ServerHello: Сервер вибирає параметри з'єднання.
Certificate: Сервер надсилає свій сертифікат.
Приклад:
Frame 6: 1514 bytes on wire
Source: 93.184.216.34 (93.184.216.34)
Destination: 192.168.1.100 (192.168.1.100)
TLSv1.2 Record Layer: Handshake Protocol: Server Hello
TLSv1.2 Record Layer: Handshake Protocol: Certificate
Client Key Exchange та зміна Cipher Spec
Клієнт відправляє Client Key Exchange та повідомлення Change Cipher Spec.
Приклад:
Frame 7: 263 bytes on wire
Source: 192.168.1.100 (192.168.1.100)
Destination: 93.184.216.34 (93.184.216.34)
TLSv1.2 Record Layer: Handshake Protocol: Client Key Exchange
TLSv1.2 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
Шифрований трафік
Після завершення рукостискання подальший трафік шифрується. У Wireshark він відображається як Application Data.
Приклад:
Frame 8: 150 bytes on wire
Source: 192.168.1.100 (192.168.1.100)
Destination: 93.184.216.34 (93.184.216.34)
TLSv1.2 Record Layer: Application Data
Перегляд деталей сертифіката
У Wireshark можна переглянути деталі сертифіката, натиснувши на повідомлення Certificate та розкривши секцію X.509 Certificate.
Приклад інформації:
Subject: CN=www.example.com
Issuer: CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US
Validity:
Not Before: Sep 1 00:00:00 2021 GMT
Not After : Dec 1 00:00:00 2021 GMT
Public Key Algorithm: RSA
Signature Algorithm: sha256RSA
Взаємодія шифрування та сертифікатів у захопленому трафіку
Сертифікати надаються сервером у відкритому вигляді, щоб клієнт міг їх перевірити.
Асиметричне шифрування використовується під час Client Key Exchange, коли клієнт шифрує Pre-Master Secret відкритим ключем сервера.
Симетричне шифрування використовується після рукостискання, і Wireshark не може розшифрувати цей трафік без доступу до сесійного ключа.
Захищені хеші (MAC) використовуються для забезпечення цілісності даних.
Декодування TLS-трафіку в Wireshark (при наявності ключів)
Якщо ви маєте доступ до приватного ключа сервера (що в реальних умовах не рекомендовано), ви можете налаштувати Wireshark для розшифровки TLS-трафіку.
Preferences → Protocols → TLS: Вкажіть шлях до приватного ключа.
Обмеження: Це працює лише з певними типами шифрів (наприклад, RSA без PFS).
У більшості випадків, особливо з сучасними шифрами, Wireshark не може розшифрувати трафік без сесійного ключа.