Выбор ciphersuites для TLS и уязвимость Logjam. Опыт Яндекса
Сейчас на фоне уязвимости Logjam все в индустрии в очередной раз обсуждают проблемы и особенности TLS. Я хочу воспользоваться этой возможностью, чтобы поговорить об одной из них, а именно — о настройке ciphersiutes. Мы уже не раз писали на Хабре о том, как внедряем шифрование трафика на сервисах Яндекса: например, об этом весьма подробно рассказывал Эльдар kyprizel Заитов, но ciphersiutes были одной из вещей, которые в тот раз остались в основном за кадром. Кстати, хочу всех успокоить и сказать, что на серверах Яндекса никогда не использовался экспортный вариант алгоритма Диффи-Хеллмана.Итак, Ciphersuite — это совокупность алгоритмов, используемых в конкретной TLS–сессии. Сюда относятся:
алгоритм выработки сессионных ключей шифрования; алгоритм, используемый для аутентификации сервера; собственно симметричный алгоритм шифрования трафика; и, наконец, алгоритм контроля целостности (MAC, message authentication code). Для того чтобы понять, какова роль каждого из алгоритмов, давайте вкратце рассмотрим процесс инициализации TLS–соединения в применении к HTTPS (разумеется, TLS возможен и для других TCP и UDP протоколов, но сейчас мы это рассматривать не будем). За подробностями можно обратиться в RFC5246.
В TLS есть собственный механизм деления на сообщения, называемый record protocol. Каждое TLS-сообщение не обязано быть равно TCP-сегменту, оно может быть больше или меньше.TLS соединение начинает клиент — пересылкой сообщения ClientHello. Самая интересная для нас часть сообщения ClientHello — как раз список поддерживаемых клиентом ciphersuite. Также клиент посылает список известных ему эллиптических кривых.
В ответ сервер пересылает сообщение ServerHello, содержащее выбранный ciphersuite:
В данном случае это TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256. Этот вариант означает, что для генерации сеансовых ключей будет использован алгоритм Диффи-Хеллмана на эллиптических кривых, аутентификация сервера будет производится с помощью RSA, а в качестве алгоритма шифрования трафика будет использоваться AES с длиной ключа 128 бит в режиме GCM. Внимательный читатель заметит, что GCM является AEAD-алгоритмом и таким образом не требует дополнительной функции MAC. Зачем же она нужна? Ответ кроется в механизме выработки сеансовых ключей, но сначала давайте обсудим некоторые варианты каждого алгоритма в ciphersuite. С полным списком всех возможных вариантов можно ознакомиться на сайте IANA.
Итак, в качестве алгоритма выработки сеансовых ключей могут использоваться:
классический алгоритм Диффи-Хеллмана, он обозначается DH и DHE; вариант алгоритма Диффи-Хеллмана на эллиптических кривых, он обозначается ECDH и ECDHE; генерация случайного числа клиентом и последующее его шифрование на публичном ключе сервера, в реальных ситуациях почти всегда применяется RSA. Разница между вариантами DH без суффикса E и с суффиксом E состоит в эфемерности ключа. В случае DHE и ECDHE ключ действительно вырабатывается в ходе полноценного DH-обмена, где параметры шифрования не сохраняются и таким образом достигается свойство PFS. В ciphersuites DH и ECDH приватный ключ сервера (и клиента, если он есть) является приватным ключом для DH-обмена и таким образом свойство PFS не достигается.В качестве алгоритма аутентификации в практических реалиях используется почти исключительно RSA, ECDSA делает первые шаги, но мы надеемся, что он будет больше распространен.
В качестве симметричных алгоритмов шифрования широко распространены AES с длиной ключа 128 и 256 бит в режимах CBC и GCM, RC4 и 3DES. Можно встретить ciphersuite с одиночным DES, CHACHA20 и даже NULL — этот означает, что никакого шифрования на самом деле применяться не будет.
В качестве алгоритмов MAC встречаются MD5, SHA1, SHA256 и, редко, SHA384.
Как было сказано выше, в случае алгоритма шифрования AES в режиме GCM контроль целостности обеспечивается собственно режимом шифрования. Поэтому необходимости в отдельной MAC–функции нет. В RFC на TLS1.2 специально указано, что помимо собственно функции аутентификации MAC-алгоритм в ciphersuite выполняет еще и роль псевдослучайной функции (PRF). Когда общее между клиентом и сервером случайное число вырабатывается за счет того или иного варианта DH или просто генерируется клиентом, оно носит название pre-master key. После получения pre-master key на его основе (а также на основе случайных значений из сообщений ClientHello и ServerHello) вырабатывается master key путем применения PRF функции: master_secret = PRF (pre_master_secret, «master secret», ClientHello.random + ServerHello.random). Впоследствии из master key с помощью той же функции PRF вычисляется весь необходимый ключевой материал: ключи для алгоритмов шифрования, ключи для MAC, инициализационные векторы.
Ciphersuites в реальной жизниТеперь, когда базовая теория понятна, давайте рассмотрим настройки ciphersuites на некоторых популярных сайтах. Для этого можно использовать сканер SSLLabs, хотя у нас в Яндексе для внутренних нужд используется написанный kyprizel инструмент. В принципе, можно использовать команду openssl s_client с ключом -cipher или попробовать cipherscan, который по сути является оберткой на bash для вызова openssl.Для того что бы тестировать варианты ciphersuites локально, удобно использовать команду openssl ciphers, которая позволит посмотреть, во что именно превратится предлагаемый набор условий для ciphersuite.
Итак, собственно, Яндекс. Список поддерживаемых сервером ciphersuites довольно велик:
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_RSA_WITH_AES_256_CBC_SHA256 TLS_RSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA TLS_RSA_WITH_RC4_128_SHA (0×5) TLS_ECDHE_RSA_WITH_RC4_128_SHA Сначала идут современные ciphersuites с выработкой pre-master ключа через ECDHE. Мы предпочитаем AES-128 в режиме GCM. Я лично не вижу большой пользы от AES256, но для yandex.ru мы сохранили этот набор шифров для более параноидальных пользователей. После различных вариантов ECDHE ciphersuites идут варианты с шифрованием AES, но без PFS. Такие варианты используются браузерами типа старой Opera (версии 12.x), и поэтому мы вынуждены их сохранить.
Затем идет два варианта с шифрованием 3DES: их мы сохраняем в первую очередь для браузеров Internet Explorer на Windows XP с установленным SP3. Internet Explorer использует системную библиотеку Schannel, и в XP с SP3 наконец появилась поддержка 3DES — устаревшего, но все еще устойчивого алгоритма шифрования. Наконец, для несчастных с Internet Explorer 6 на XP мы сохраняем шифры RC4 — других вариантов на этой платформе просто нет. При этом мы осознаем вероятность того, что этот шифр уязвим, поэтому доступен он только в случае хендшейка по протоколу SSLv3. Если клиент подключается с более современным протоколом — TLS 1.0, TLS 1.1 или TLS 1.2 — ciphersuite на основе RC4 не предлагается.
Серверы поиска таким образом предлагают трейдофф между безопасностью для современных клиентов и необходимостью поддерживать старые.
Иная ситуация на серверах Яндекс.Почты. Здесь, например, команда приняла продуктовое решение не поддерживать IE6 (даже в так называемой «легкой» верстке) и это отразилось в поддержке на уровне TLS:
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA Логика сохранена той же, но трейдофф сдвинут в сторону большей безопасности и меньшей совместимости с устаревшими браузерами. Сначала — современные ciphersuite для TLS1.2: наш любимый ECDHE + AES128 в режиме GCM, затем то же самое, но в режиме CBC и, наконец, вариант с более слабым SHA1. Следующие три варианта — то же самое, но без PFS. Замыкает набор ciphersuite для IE8: 3DES в режиме CBC с SHA1 и без PFS. Очень хотим от него отказаться, поэтому в Почте мы начали кампанию по обновлению браузеров пользователей. Если вы настраиваете компьютеры своим родителям, не поленитесь — установите современный браузер. Проделайте то же самое и в своей организации.
Еще один вариант — Яндекс.Паспорт. Здесь мы пробовали сохранить классический DH, поскольку замечали ситуации, когда находились браузеры, которые все таки предпочитали его и, возможно, не имели поддержки ECDH (одно время это относилось к Firefox на RedHat Linux, где по юридическим соображениям отсутствовали протоколы с эллиптической криптографией). При этом задолго до публикации атаки Logjam мы понимали необходимость выравнивания длин ключей и бесполезность использования 1024-битного DH при 2048-битных RSA ключах в сертификатах. Поэтому на passport.yandex.ru доступен DHE, но 2048-битный, сгенерированный специально для этого случая, и сервис не подвержен Logjam. Остальная логика такая же: сначала ECDH с AES в различных вариантах, потом DH с AES, потом AES без PFS и, наконец, fallback в 3DES без PFS.
Давайте посмотрим и на «их нравы». Вот пример с gmail.com.
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_RC4_128_SHA TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_RC4_128_SHA TLS_RSA_WITH_RC4_128_MD5 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_RSA_WITH_AES_256_CBC_SHA256 TLS_RSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA Мне в целом понятна логика приоритетов: сначала ECDH и AES. Обратите внимание, что Google решил попробовать шифр CHACHA20, о котором я писал выше. Мне кажется, что главная его цель — облегчить нагрузку на CPU (и, соответственно, расход энергии) в смартфонах на Android. Что и говорить, доминирование имеет свои преимущества — контролируя и сервис, и платформу можно делать недоступные другим вещи. Интересно, что Google использует свой форк OpenSSL под названием BoringSSL. Интересное его свойство — возможность задавать ciphersuites равных приоритетов. Так в этом случае (хотя ssllabs этого не показывает), TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 и TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 имеют равный приоритет и среди них клиент определяет, какой ciphersuite считает приоритетным.
Вот twitter.com:
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA И снова понятная логика, очень похожая на нашу в Почте: сначала ECDHE, зачем AES без PFS и fallback на 3DES.
Логика на vk.com мне непонятна. Кажется, тут просто взяли все шифры и выкинули из них MD5 и RC4. Думаю, похожий набор можно получить командой openssl ciphers 'ALL:! RC4:! MD5'. Шифр CAMELLIA? Are serious?
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 TLS_DHE_RSA_WITH_AES_256_CBC_SHA TLS_DHE_RSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_CBC_SHA256 TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA TLS_RSA_WITH_CAMELLIA_256_CBC_SHA TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA TLS_RSA_WITH_CAMELLIA_128_CBC_SHA У mail.ru сначала ECDHE, потом DHE, потом — шифры без PFS, но опять же — CAMELLIA, SEED. Кажется, и тут никто не выбирал ciphersuites, а положился на варианты, предлагаемые OpenSSL по умолчанию.
Интересно, что до недавнего времени сервер nsa.gov имел очень слабый набор ciphersuites, самым лучшим вариантом там был RC4 без PFS, но сейчас ситуацию исправили с той же самой логикой, что и у нас: ECDHE и AES, RSA и AES, fallback на 3DES. Аналогично выглядит https на сайте ЦРУ. Забавно, что на сайтах ФСБ и СВР вообще не работает https.
Впрочем, по моей личной оценке, сайтом с самыми плохими ciphersuites в интернете был сайт Госуслуг правительства Москвы login.mos.ru. В свое время он предлагал ciphersuite TLS_NULL_WITH_NULL_NULL — то есть без аутентификации и без шифрования. Впрочем, сейчас приняты меры: задержка на установку TLS соединения с sslabs.com установлен таким образом, что сканнер отваливается по таймауту. Но и ciphersuites поправлены, хотя высшим приоритетом стоят RC4-MD5, RC4-SHA и 3DES-SHA, в списке можно найти ECDH — это можно проверить вручную командой openssl s_client с ключом -cipher.
Рекомендации по выбору ciphersuite Какие настройки можно порекомендовать обычному сайту? Вот такой рекомендованый конфиг nginx мы используем в Яндексе по умолчанию: ssl_prefer_server_ciphers on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers kEECDH+AESGCM+AES128: kEECDH+AES128: kRSA+AESGCM+AES128: kRSA+AES128:! RC4:! aNULL:! eNULL:! MD5:! EXPORT:! LOW:! SEED:! CAMELLIA:! IDEA:! PSK:! SRP:! SSLv2; Если необходима поддержка IE8 на XP, можно использовать такой набор, он включит 3DES:
ssl_ciphers kEECDH+AESGCM+AES128: kEECDH+AES128: kRSA+AESGCM+AES128: kRSA+AES128: kRSA+3DES:! RC4:! aNULL:! eNULL:! MD5:! EXPORT:! LOW:! SEED:! CAMELLIA:! IDEA:! PSK:! SRP:! SSLv2; Если нужна поддержка IE6 на XP, можно включить RC4, но в таких случаях мы рекомендуем нашим системным администраторам проконсультироваться со службой информационной безопасности, чтобы точно представлять свои риски. Я не уверен, что каким-то сайтам за пределами первой полусотни самых популярных в рунете действительно необходима такая подержка.
Кстати, найдете интересные настройки ciphersuite в интернете, пишите.