# TLS

## Що це таке

TLS, Transport Layer Security, — це протокол, який клієнт і сервер виконують
перед обміном даними застосунку, щоб усе подальше лишалося приватним, не
змінювалося непомітно й потрапляло саме до тієї сторони, до якої звертався
клієнт. У меню продуктів і в магазинах сертифікатів його досі часто називають
SSL, за назвою Secure Sockets Layer, протоколу, на зміну якому прийшов TLS.
RFC 7568 у червні 2015 року визнав останню версію SSL застарілою, тож усе, що
сьогодні зветься SSL, усередині є TLS або принаймні має ним бути.

TLS розташований між протоколом застосунку й транспортом під ним. HTTPS — це
HTTP усередині TLS-з'єднання, а той самий шар захищає надсилання пошти, IMAP,
з'єднання з базами даних і протокол Gemini. HTTP/3 іде далі: він працює поверх
QUIC, що вбудовує рукостискання TLS 1.3 просто в транспорт, а не кладе його
поверх TCP, як описує RFC 9001.

Чинна версія — TLS 1.3 з RFC 8446, опублікованого в серпні 2018 року, який
замінив специфікацію TLS 1.2. З'єднання починається з рукостискання. Клієнт
надсилає ClientHello з переліком версій, наборів шифрів (cipher suites) і
ключових часток, які він підтримує, а також Server Name Indication (SNI) — ім'я
хоста, до якого він звертається, щоб одна адреса могла обслуговувати багато
сайтів. Сервер обирає, відповідає власною ключовою часткою, і з цієї миті все
шифрується, зокрема й сертифікат, який він показує. Ланцюжок сертифікатів
пов'язує ключ сервера з центром сертифікації, якому клієнт уже довіряє. Клієнт
перевіряє ланцюжок, ім'я та дати, а сервер доводить, що володіє відповідним
закритим ключем, підписуючи рукостискання.

Версію 1.3 від 1.2 відрізняють три речі. Повне рукостискання займає один обмін
туди й назад замість двох. Кожен обмін ключами ефемерний, тож запис
сьогоднішнього трафіку лишається закритим, навіть якщо закритий ключ сервера
витече наступного року; ця властивість називається прямою секретністю (forward
secrecy). І клієнт, що повертається, може надіслати «ранні дані» вже в першому
повідомленні — це називають 0-RTT, — але RFC прямо називає ціну: такі дані не
мають ні прямої секретності, ні захисту від повторного відтворення в іншому
з'єднанні.

## Чому це важливо

Чи використовувати TLS, давно вирішено. Відкритими лишаються два питання: які
версії приймати і де закінчується зашифроване з'єднання.

Спершу версії. RFC 8996 від березня 2021 року забороняє використовувати TLS 1.0
і 1.1. RFC 9325, чинна найкраща практика (BCP 195), вимагає підтримки 1.2,
рекомендує 1.3 і велить віддавати перевагу 1.3, коли його мають обидві сторони.
Вона ж каже, що 1.2, налаштований за її вказівками, такий самий безпечний, як
1.3: обмін ключами ECDHE заради прямої секретності, AES-GCM і жодного набору з
режимом CBC. Тож реальний вибір — між «1.2 і 1.3» та «лише 1.3». Сервіс лише з
1.3 має меншу поверхню атаки й коротшу конфігурацію, але відсікає кожного
клієнта, що вміє щонайбільше 1.2: старіший телефон, платіжний термінал,
інтеграцію партнера на старому середовищі Java. Таке рішення легко ухвалити на
фактах. Кілька тижнів журналюйте узгоджену версію, а тоді вирішуйте за цифрами,
а не за тим, що звучить сучасно.

Потім термінування. Там, де закінчується TLS, лежить закритий ключ, і трафік
знову стає відкритим текстом. Є три поширені місця:

- **CDN або хмарний балансувальник навантаження.** Постачальник тримає ключ або
  сертифікат, який сам випустив, бере на себе навантаження рукостискань і бачить
  кожен запит відкритим текстом. Ділянці від нього до вихідного сервера потрібен
  власний TLS, інакше вона йде мережею незашифрованою.
- **Зворотний проксі на хості,** наприклад Nginx, Apache, HAProxy чи Caddy.
  Один процес тримає ключі всіх сайтів машини й передає запити без шифрування
  застосункам за ним через loopback або локальний сокет.
- **Сам застосунок.** Кожен сервіс має власний ключ. Це пасує трафіку між
  сервісами та взаємному TLS (mutual TLS), де сертифікат показує й клієнт, і
  водночас множить місця, де сертифікат треба поновлювати.

Більшість інфраструктур поєднує всі три. Важливо, щоб для кожної ділянки хтось
міг сказати, де лежить відкритий текст і хто здатен його прочитати.

## Як це виглядає на практиці

Власний робочий хост компанії показує, як мало потребує термінування TLS. Це
хмарний примірник з одним ядром, 512 МБ пам'яті, з яких можна використати
близько 464 МБ, і 10 ГБ диска. На ньому
[один вебсервер термінує TLS для всіх семи доменів](/uk/portfolio/ran-the-whole-company-on-one-512mb-host-109/)
поруч із хостингом git-репозиторіїв, onion-службою Tor, сервером Gemini,
сервером Gopher, зашифрованими резервними копіями та блокуванням вторгнень. Це
термінування на хості в найпростішому вигляді: один вебсервер відповідає за всі
сім сайтів, і їхнє шифрування не вимагає ані окремої машини, ані окремого
сервісу. Проєкт виходив із пам'яті як головного обмеження, і все з цього
переліку, разом із термінуванням, вміщується в ті 464 МБ.

Правило, за яким працює компанія, записане на її
[сторінці безпеки](/uk/security/): шифрування під час передавання всюди, а
сертифікати випускаються й поновлюються без участі людини, і моніторинг стежить
за кожним поновленням. Пояснення там таке: найпоширеніша причина збоїв TLS —
сертифікат, строк якого спливає непомітно. Нижче зібрано збої, що лишаються,
коли поновлення вже працює саме.

## Де виникають проблеми

**Частина клієнтів обривається з помилкою рукостискання, хоча браузери
під'єднуються без проблем.** Сторони не мають спільної версії чи набору шифрів.
Хтось звузив сервер до 1.3 або до короткого списку наборів, і старішому клієнту
нема чого запропонувати; або сервер, що досі пропонує лише набори CBC,
натрапляє на клієнта, який від них відмовився. Повідомлення звучить як
«handshake failure» чи «protocol version» і майже нічого не пояснює. Перевірте
кожну версію ззовні:

```sh
openssl s_client -connect example.com:443 \
    -servername example.com -tls1_2 </dev/null
```

Журналюйте узгоджені версію й набір шифрів, перш ніж щось звужувати, і тримайте
1.2 з ECDHE та AES-GCM поруч із 1.3, доки журнали не покажуть, що ним ніхто не
користується.

**Браузери довіряють сертифікату, а скрипти, curl і мобільні застосунки його
відхиляють.** Сервер надсилає власний сертифікат без проміжного, що пов'язує
його з кореневим. Браузери часто заповнюють прогалину проміжними сертифікатами,
які вже бачили, або самі завантажують відсутній; більшість бібліотек TLS не
робить ні того, ні іншого й повідомляє про невідомого видавця. Налаштуйте повний
файл ланцюжка — спочатку сертифікат сервера, потім проміжні — і перевіряйте
клієнтом без кешу: рядок з `openssl s_client` вище показує ланцюжок, який сервер
справді надіслав.

**Перевірку сертифікатів вимикають «тимчасово», і це налаштування потрапляє в
робоче середовище.** Тестовий сервер із самопідписаним сертифікатом або
корпоративний проксі, що перепідписує трафік, — і хтось додає `verify=False`,
`curl -k`, `InsecureSkipVerify` чи `NODE_TLS_REJECT_UNAUTHORIZED=0`. З'єднання
лишається зашифрованим, але з будь-ким, хто відповість: будь-хто посередині може
показати власний сертифікат і прочитати все. Додайте потрібний сертифікат центру
сертифікації до сховища довіри клієнта або вкажіть його клієнту явно, а в CI
зробіть ці прапорці причиною падіння збірки.

**Частина відвідувачів отримує сертифікат зовсім іншого сайту.** Сервер показує
типовий сертифікат, коли ClientHello називає хост, для якого в нього немає
конфігурації, або взагалі не називає хоста. Так буває, коли новий домен
спрямовують на адресу раніше, ніж з'явився його серверний блок, і коли зонд
моніторингу чи старий клієнт не надсилає SNI. Браузер показує помилку імені, а
на спільному хості заодно повідомляє відвідувачу, які ще сайти там живуть. Дайте
кожному публічному імені власний блок і сертифікат, що його покриває, а типовий
блок нехай відхиляє рукостискання замість показувати чужий сертифікат.

**Платіж чи інший запит виконується двічі.** Термінатор приймає ранні дані
0-RTT, усередині них приходить POST, і зловмисник або автоматичний повтор у
мережі надсилає ті самі байти знову в новому з'єднанні. RFC 8446 дозволяє
серверу приймати ранні дані й лишає захист від повторів між з'єднаннями
застосунку. Приймайте ранні дані лише для запитів, які безпечно повторювати, або
нехай термінатор відхиляє їх для всього іншого; RFC 8470 визначає для цього
статус 425 Too Early.

## Що почитати далі

- [RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3](https://www.rfc-editor.org/rfc/rfc8446)
  — рукостискання, рівень записів і додаток про те, чому дані 0-RTT можна
  відтворити повторно.
- [RFC 9325: Recommendations for Secure Use of TLS and DTLS](https://www.rfc-editor.org/rfc/rfc9325)
  — BCP 195: які версії дозволяти, які набори шифрів для 1.2 залишати, і
  правила для SNI.
- [RFC 8996: Deprecating TLS 1.0 and TLS 1.1](https://www.rfc-editor.org/rfc/rfc8996)
  — формальне завершення двох старіших версій і його причини.
- [RFC 8470: Using Early Data in HTTP](https://www.rfc-editor.org/rfc/rfc8470) —
  як термінатор і сервер домовляються, які запити можна надсилати в 0-RTT, і
  статус 425.

<https://engineer.company/uk/glossary/tls/>
