Введение в TLS для п̶р̶а̶к̶т̶и̶к̶о̶в̶ Патриков (часть 1)
Как вы, возможно, уже знаете, это Патрик. Он морская звезда, а значит, можно, не оскорбляя его, сказать, что руки у него растут из одного места. Еще Патрик очень практичный и сразу забывает всё, что ему не нужно – но если что-то ему нужно, он хочет это знать (потому что ему это нужно!). Спойлер: здесь Патрик пытается сделать TLS Handshake.
Эта статья написана для Патрика и таких, как он. Она родилась из презентации, впервые показанной на нашем внутреннем образовательном Plesk TechTalk, где сотрудники в доступной форме делятся друг с другом информацией об интересных технологиях, процессах и решениях. Поэтому картинки в этой статье будут похожи на слайды :) Автор оригинального текста доклада — program manager Plesk Руслан Косолапов.
Обычно все материалы по TLS охватывают какой-то маленький аспект, но не общую картину. Это не очень практично и у Патрика от такого болит голова. Здесь всё будет по-другому: коротко, применимо «в быту» и по возможности исчерпывающе.
Что такое TLS и зачем он Патрику
TLS (Transport Layer Security) – это протокол защиты транспортного уровня. Он нужен для того, чтобы никто не мог вас «прослушать» и узнать какую-то важную информацию (чаще всего пароли, если говорить о работе в сети). А еще для того, чтобы защититься от подделывания и модификации трафика в процессе передачи. Именно в этих двух вещах состоит назначение TLS.
Для наглядности давайте рассматривать TLS handshake как звонок Патрика Губке Бобу. Во время звонка кто-то может подслушать разговор (стоя рядом с Патриком либо включившись в середине линии), и вообще на другом конце может быть не Губка Боб – все эти проблемы актуальны. И чтобы их порешать, Патрик хочет использовать TLS.
Вкратце, верхнеуровневый handshake выглядит так:
Патрик: Хочу использововать TLS, шифры-версии такие-то.
Губка Боб: Ок, давай использовать шифры-версии такие-то.
После этого Губка Боб отсылает сертификат, Патрик его проверяет, говорит что все отлично, делается сессионный ключ (на самом деле их два, но это неважно). Почему используется сессионный ключ, а не ассиметричное шифрование — потому что это быстрее. После этого они начинают говорить на непонятном для расшифровки языке. Таким образом, всё защищено.
Кажется, что всё просто. Как работает на железе – нам не так важно. Но если начать задумываться – а Патрик начинает задумываться! – то возникает вопрос, как вообще договориться, что мы будем использовать TLS? Ведь когда-то TLS не было, а были только обычные протоколы – SMTP, HTTP. Как сказать, что надо по TLS? И здесь у нас в индустрии всё как обычно – есть много путей!
Сначала хотели использовать определенный порт, который будет подразумевать использование на нем TLS. Какие у этого минусы? И почему потом появился эксплицитный (явный) метод начала TLS-сессии? Причин несколько:
- Портов нужно много — а порты такая вещь, тратить которую не хочется. Потому что чем их больше, тем сложнее настраивать файрволл.
- Сервер может это проигнорировать – законнектился на 443 порт, а там никакого TLS нет, только HTTP без всякого HTTPS.
- До того, как соединение будет установлено, вы не сможете узнать, поддерживает сервер TLS или нет.
Всё это привело к появлению эксплицитного метода – когда мы коннектимся на обычный порт, а потом повышаем нашу сессию до TLS. Для разных сервисов в протоколе есть разные команды, например для SMTP есть отдельная команда на уровне протокола SMTP – STARTTLS. У HTTP такая шутка тоже есть, она называется Upgrade: TLS/1.0. На уровне протокола проще понять, поддерживает сервер TLS или нет.
Остановимся немного подробнее на разных видах соединений и на том, как для них обстоят дела с TLS.
Connect: HTTP
Всё было бы легко, если бы, как всегда, не было нюансов. В случае с HTTP растущие требования к безопасности обеспечивают постоянную эволюцию процесса работы с TLS. Сначала был редирект на HTTPS, и это делалось просто в заголовке. Это оставляло лазейку для уязвимостей, поэтому товарищи из Google придумали HSTS (HTTP Strict Transport Security). Это такой заголовок в HTTP-ответе, который говорит браузеру: «запомни, пожалуйста, что когда ты приходишь на этот домен, иди сразу на HTTPS, даже если человек сказал идти на HTTP». Таким образом, нет никакого редиректа и всё происходит гораздо безопаснее. Кроме этого, у Google есть еще одна инициатива – можно оставить заявку, чтобы твой сайт добавили в список для Google Chrome «всегда ходить по HTTPS», вне зависимости от всяких заголовков.
Кратко: HSTS решает проблему уязвимостей при редиректе с HTTP на HTTPS, поэтому почти все браузеры поддерживают HSTS, что хорошо.
Connect: экзотика (новые версии HTTP и не только)
В HTTP/2 дела с TLS обстоят хорошо: он используется всегда (так сейчас сделаны браузеры). Кроме того, TLS в HTTP/2 должен быть свежим — то есть иметь версию 1.2+.
Скорее всего, уже очень скоро Google продавит повсеместное использование HTTP/3, уже сейчас он принят стандартом IANA. История его появления и развития довольно запутанная; главное, что стоит запомнить Патрику:
- HTTP/3 – это всегда TLS 1.3+.
- В основе HTTP/3 лежит QUIC – это такой протокол поверх UDP, который, по мнению Google, лучше, чем TCP. Собственно, до того, как было окончательного утверждено название HTTP/3, протокол назывался HTTP-over-QUIC.
Еще есть интересный протокол SCTP, который используется в основном в телекоме. Поверх него используют и TLS, и DTLS (это такой TLS для UDP).
Кратко: года через 2 везде будет использоваться QUIC (то есть HTTP/3), а сейчас везде уже должен быть HTTP/2, но в действительности он еще не везде.
Connect: Mail
Многие клиенты считают, что на 587-м порту должен быть TLS, но здесь тоже есть нюансы: кто-то ожидает TLS по умолчанию, а кто-то ждет явного запроса STARTTLS от клиента. Из-за этого в разных сочетаниях mail-сервера и mail-клиента иногда возникают нежелательные эффекты. Например, клиент заходит на 587 порт, ожидая, что там будет TLS, в то же время сервер ждет, что клиент сам явно запросит STARTTLS. Ничего не получив, клиент откатывается на 25-й порт. В итоге – молчаливое переключение на небезопасное соединение по SMTP. При тестировании и разработке стоит помнить о таких эффектах сочетаний клиента и сервера. В Autodiscaver есть разные возможности указать про TLS: как оно должно быть, что ожидается и что делать. Многие mail-клиенты понимают эти вещи.
Кратко: с поддержкой TLS в mail-серверах и mail-клиентах все в общем и целом нормально, но в частных случаях могут быть проблемы и расширения TLS поддерживаются не очень хорошо.
Connect: FTP
Здесь мало что можно сказать. Основная проблема – SNI (это когда на одном IP разные домены). На уровне FTP имя домена не передается. В эксплицитном варианте работать не может, потому что некуда его писать. Существует несколько вариантов решения — одни предлагают так, другие так, общее решение пока не принято, стандарта нет.
Кратко: поддержка TLS для FTP в каком-то виде есть (FTPS, SFTP — аналог FTP, реализованный через SSH), но некоторые аспекты не охвачены в силу технических ограничений самого FTP.
TLS Handshake
Итак, теперь мы знаем, как инициировать общение с использованием TLS в разных соединениях и Патрик смог сообщить о своем желании Губке Бобу. Как только они договорились, что будут использовать TLS, производится TLS Handshake. Его результатом должна стать договорённость клиента и сервера о том, как они всё это шифруют. Кроме этого, клиент должен убедиться, что сервер именно тот, какой надо. Иногда сервер также проверяет клиента (но значительно реже).
Шифры и версии
Как уже говорилось, на первом этапе выбирается, какая версия TLS и какие шифры будут использоваться для шифрования. Обычно шифр выглядит так:
Набор шифров есть в реестре IANA, а в протоколе TLS в бинарном виде лежит только его ID. Как видно на рисунке, здесь не просто (и не только) шифр, а еще режим его работы и другие детали, необходимые для TLS-handshake. Углубляться в подробности Патрику не нужно. Всё, что важно на данном этапе, это запомнить, что эти буквочки — это хорошо (а остальные — нехорошо):
- DHE
- ECDHE
- AES128
- AES256
- RSA
- ECDSA
- CBC
- GCM
- SHA256
- SHA383
- CHACHA20
- POLY1308
Картинка для запоминания хороших шифров:
Если запоминать тяжело, есть хорошие сервисы, которые могут вам про это рассказать, например, сервис от Mozilla ssl-config.mozilla.org.
Тут же можно посмотреть, что где и как поддерживается – за этим ребята из Mozilla пытаются следить.
Интересная деталь: клиент передает шифры в порядке приоритета согласно своим предпочтениям, но решение остается за сервером – он выбирает шифр, который ему кажется наилучшим из списка поддерживаемых клиентом.
Также обе стороны указывают максимальную поддерживаемую версию протокола – в данном случае Патрик более продвинутый, чем Губка Боб.
Собственно сертификат
Вместе с ответом «Давай делать вот так» сервер посылает свой сертификат или сертификаты – их может быть много.
Что представляет собой сертификат? Это связь информации (subject) – чаще всего это имя домена или организации, — и публичного ключа (public key). То есть, сертификат говорит: «Чувак, мой public key вот такой. Сейчас мы с его помощью договоримся о сессионных ключах». Также с его помощью можно проверять подписи сертификатов или еще чего-либо. То есть в принципе можно было бы использовать не сертификаты, а реестры, где эта связь указана. И на самом деле шаги в этом направлении продолжаются, потому что механизм Certificate Authority считается не очень хорошим, просто ничего другого нет.
Таким образом, сертификат – это структура 'Subject: Public key' плюс подпись того ишьюера (issuer в транслитерации на русский выглядит ужасно, но самый близкий синоним здесь — не очень близкий по контексту «эмитент»), который этот сертификат выписал. У ишьюера тоже есть сертификат и связь кого-то с чем-то. Проверить сертификат на правильность можно, взяв публичный ключ ишьюера и проверив подпись. Подделать в итоге здесь ничего нельзя.
Давайте пробежимся по сертификату и посмотрим, какие с ним могут быть проблемы.
Во-первых, serial Number подразумевает уникальность только в пределах ишьюера, хотя некоторый софт считает, что он уникален во всей вселенной. К счастью, чаще всего он действительно полностью уникален.
Также в сертификате указывается, какие алгоритмы используются для шифрования и подписи: RSA или ECDSA — то есть, какую криптографию использовать для работы с этим публичным ключом. Основная разница между RSA и ECDSA в том, что математический принцип работы ECDSA основан на эллиптических кривых, а RSA — просто на натуральных числах, поэому он медленнее и для того, чтобы его нельзя было взломать, используются огромные биты ключей (3-4 тысячи). А для ECDSA достаточно ключа длиной в 300 бит и работает он быстрее. Поэтому многие переходят на ECDSA – handshake сам по себе тяжелый и хочется его сократить. ECDSA можно попросить при выписке сертификата, и если ишьюер его поддерживает, он вам сделает. А вот подпись сертификата зависит от того, какой приватный ключ есть в данный момент у ишьюера, а не от того, попросили вы ECDSA или RSA. Поэтому браузеры могут показывать, что в подписи одно, а в публичном ключе другое и не надо бояться, если в подписи не ECDSA.
Как же получить сертификат?
Вкратце – вот так:
Патрик говорит центру сертификации (Certificate Authority): мне нужен сертификат. Этот человек (или организация) проверяет, действительно ли это Патрик. Проверки могут быть самыми разными. Конечно, Патрик как клиент может и не иметь сертификата, а вот если сертификата нет у сервера, то никакого TLS не будет. Проверяется, всё ли правильно указано в заявке сертификата, действительно ли Патрик владеет этим субъектом (subject), на который просит сертификат. Этим занимаются вышестоящие удостоверяющие центры (Certificate Authority centres) – условные люди, которым все верят. Чтобы выписать сертификат, нужно составить CSR (Certificate signing request, запрос на выдачу сертификата).
Это тоже структура, работать с которой довольно сложно, потому что сервисов, позволяющих всё задать, указать, проверить и посмотреть, мало.
Итого, мы генерируем пару публичный ключ: приватный ключ, но отдаем только публичный, а приватный прячем. Затем формируем Certificate Signing Request и подписываем своим приватным ключом. Отправляем всё это центру сертификации, и тот начинает проверку. Она может быть разной, для особо крутых сертификатов есть специальные хитрые процедуры, но мы остановимся на общем случае.
CAA RR
Есть такая проблема, что люди, которым все верят, иногда не очень хорошие. Одна из причин того, что Symantec стал частью DigiCert, состоит в том, что он (Symantec) выписывал сертификаты без запроса от владельцев домена. Так делать нельзя, обидно было всем, но больше всех самому Symantec, потому что пришлось продать свой бизнес. Для того, чтобы сервер меньше зависел от таких недобросовестных товарищей, есть такая штука как CAA RR – запись в DNS, где написано, кому владелец разрешает выписывать сертификаты для своего домена. Эта функция есть и в Plesk, она пока используется мало, примерно как DNSSec, – но тем не менее. Все центры сертификации договорились проверять эту запись и если в ней указано, что этому центру сертификации выписывать сертификат нельзя, он скажет: «ты не прошел валидацию, у тебя в САА RR написано, что я тебе не могу сертификат выписывать» — и не выпишет. Если записи нет – то можно. Сейчас Google толкает инициативу, чтобы клиенты проверяли пришедший сертификат на соответствие CAA RR записям. Споры пока продолжаются.
Также CAA RR с того момента, как мы делали их поддержку в Plesk, расширились указанием методов валидации (то есть, можно также указать здесь, каким методом ты валидируешь, что этот домен твой) и Account URI (Uniform Resource Identifier). Популярный среди пользователей Plesk Let’s Encrypt уже всё это поддерживает (молодец!).
Всё это работает для любого типа сертификатов, а так как дальше речь пойдет про различия, пора рассказать про типы подробнее.
Типы сертификатов
Их три:
Domain validation
Субъектом является домен, то есть здесь мы проверяем только его. Раньше, когда не было автоматических валидаторов, валидация происходила в основном по e-mail через сервис Whois. Это считалось достаточным основанием для того, чтобы считать, что ты владелец этого домена. Потом придумали проверять через DNS – на e-mail тебе писали: «а добавь-ка в DNS такую-то запись». Еще попозже появились автоматические методы (про ACME поговорим чуть дальше).
Organization validation
В поле «subject», кроме доменного имени, указывается еще и имя организации. Проверка состоит в валидации, принадлежит ли домен данной организации и работает ли там тот, кто пришел за сертификатом. Как это делается: по реестрам организации ищут, звонят, просят что-то сделать (телефон оказался верным, правильный человек ответил – значит, скорее всего всё хорошо).
Extended validation
То же, что и OV, только круче. Тут всё очень регламентированно – документ на 40 страниц в духе «в пункте 5.6.8 должно быть следующее: …» и т.д. Проверяется много всего – страна, департамент (если указан в заявке), а иногда даже выезжает специальный человек, чтобы посмотреть глазами. В чем практическая разница? Практически все браузеры перестали различать OV и DV, и это плохо, потому что в таком случае не показывается название организации. В результате никто не мешает создать домен aliepxress.ru, нарисовать такую же страницу и воровать кредитные карточки. И будет абсолютно легитимно создать любой подобный домен и получить на него DV сертификат.
Пример с EV – здесь видно название организации, так что если кто что и украдет, пользователь будет знать, что это была корпорация Valve Corp, а зарегистрировать корпорацию несколько сложнее, чем домен (больше проверок).
Однако всё идет к тому, что и EV перестанут отличаться, на мобильных устройствах уже не видно и надо нажимать отдельную кнопочку, и в Safari тоже. Google Chrome пока держится (UPD — уже нет! пришлось делать скрин из IE). Аргументация тех, кто не показывает: «если волнуетесь, нажмите и посмотрите», но никто, естественно, не нажимает.
Получение сертификата: автоматизация
Теперь поговорим об автоматизированном получении DV сертификатов. Для наглядности посмотрим, как это делает наш любимый Let's Encrypt. У него вообще хорошая документация, если кому интересно, и даже на русском.
ACME
ACME (Automatic Certificate Management Environment) — это протокол, созданный для автоматизации и стандартизации процесса получения сертификата.
Как в случае с ACME доказывается, что ты владелец домена? Ты говоришь: хочу сертификат и указываешь вид автоматической валидации – например, ACME HTTP-01. Let’s Encrypt просит тебя положить данные в файл, и если ты смог положить файлы на свой домен (а Let’s Encrypt смог их оттуда забрать по HTTP), наверное, ты и правда его хозяин. Сейчас такой подход подвергается критике, в том числе от Google, за то, что не защищает от фишинга. То есть, при ручной валидации домен aliepxress.ru скорее всего вызовет подозрения, а вот Let’s Encrypt самостоятельно так пока не умеет (или умеет, но плохо).
DNS-challenge
Кроме ACME, есть еще DNS-challenge. Например, тебе говорят: заведи в своей DNS-зоне txt-запись, положи в нее данные. Есть и другие способы, но мало распространённые, а один вообще отменили, потому что он оказался уязвимым. Что у нас в Plesk: wildcard-сертификаты (которые могут быть выписаны только по DNS-challenge) у многих людей не работают, потому что очень часто Plesk не управляет DNS-зонами домена и экстеншн Let’s Encrypt не может автоматизировать создание записи в DNS-зоне.
Еще два слова о Let's Encrypt
Важный аспект в работе с сертификатами Let's Encrypt – лимиты. В случае сомнений (или подозрений, что они достигнуты) лучше всего пройти по ссылочке: letsencrypt.org/docs/rate-limits
Иногда их обновляют. Есть неочевидные лимиты, про которые люди забывают: чаще всего, судя по обращениям в поддержку, они сталкиваются с лимитом в 100 доменных имен в сертификате. Еще у Let’s Encrypt есть staging-сервер и там лимиты больше, но такие сертификаты считаются не доверенными (non-trusted) и для браузера они аналогичны самоподписанным. На практике с лимитом в 100 имен к нам приходят редко (при том, что у сайтов на Plesk в общей сложности 1 300 000 Let’s Encrypt сертификатов). Медиана, согласно нашей статистике, – 20 имен на сертификат. Так что, если что-то не работает, посмотрите – возможно, достигнут лимит. У Let’s Encrypt хороший error reporting, и обычно можно понять, что произошло.
Что дальше?
Итак, после того, как сертификат получен, сервер передает данные сеансового ключа – это то, с помощью чего дальше будет осуществляться шифрование. Если сервер считает, что нужно аутентифицировать клиента (например, доступ открыт только определенному кругу лиц), он может спросить: клиент, кто ты? И тогда клиенту надо будет послать свой сертификат. После получения сообщения ServerHelloDone клиент понимает, что пора проверять сертификаты и работать с ключами.
Всё, о чем мы говорили, до TLS 1.3 идет по открытому каналу, и все эти штуки может видеть кто угодно. С этим связаны несколько интересных атак, о которых вы можете почитать сами.
Во второй серии части статьи мы узнаем, как клиент проверяет сертификат.