Много где написано о том, как получить 100% и A+ по тесту от Qualys. При всём при том практически везде директивы ssl_ciphers
и подобные даются как эдакие магические строки, которые нужно просто вставить, и надеяться, что автор не подводит вас под монастырь. Эта статья призвана исправить это недоразумение. По прочтению этой статьи директива ssl_ciphers
потеряет для вас всякую магию, а ECDHE и AES будут как друзья да браться.
Подготовка
Работать будем с Debian 8.7. Если у вас другой дистрибутив, то версии должны быть такие же или более новые.
# lsb_release -d
Description: Debian GNU/Linux 8.7 (jessie)
# openssl version
OpenSSL 1.0.1t 3 May 2016
# nginx -V
nginx version: nginx/1.6.2
Настроим nginx для получения сертификатов от Let's Encrypt по инструкции, но только до получения сертификата для нашего домена.
certbot certonly -d example.com -d www.example.com
Конфиг используем минимальный. Ничего лишнего. Всё по умолчанию.
server {
server_name www.example.com example.com;
listen 443 ssl default_server;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
}
Теперь прогоним тест для этого сервера.
С настройками по умолчанию результат так себе. На четвёрку, если по-нашему. Ругаются на слабые параметры для обмена ключами по алгоритму Диффи — Хеллмана (далее просто DH).
Можно было бы сделать усиленные параметры, но такие параметры и скорости не добавляют, и некоторыми старыми клиентами поддерживаются. Те же старые клиенты поддерживают и протокол DH на эллиптических кривых (ECDHE), значит мы ничего не теряем и даже приобретаем в скорости, если вслед за Google, Facebook, Mozilla и CloudFlare полностью откажемся от медленных EDH шифров в пользу ECDHE.
Дальше просто. Нужен список рекомендованных шифров.
Для сертификата с ключем RSA из того списка нужны шифры только с проверкой подлинности через RSA.
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-RSA-AES128-SHA
ECDHE-RSA-AES256-SHA
ECDHE-RSA-AES128-SHA256
ECDHE-RSA-AES256-SHA384
DHE-RSA-AES128-GCM-SHA256
DHE-RSA-AES256-GCM-SHA384
DHE-RSA-AES128-SHA
DHE-RSA-AES256-SHA
DHE-RSA-AES128-SHA256
DHE-RSA-AES256-SHA256
Из них исключим шифры слабее 256 бит, и шифры DHE. Перечислим оставшиеся в конфигурационной директиве.
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES256-SHA384;
Но одного этого будет недостаточно. Нужен ключ минимум на 4096 бит.
certbot certonly --renew-by-default --rsa-key-size 4096 -d example.com -d www.example.com
И другая кривая. В используемой версии OpenSSL можно выбрать только одну. Выберем самую надёжную из популярных.
ssl_ecdh_curve secp384r1;
Для оценки с плюсом добавим HSTS.
add_header Strict-Transport-Security "max-age=31536000";
Наконец, отключим старые протоколы для 100% оценки по графе Protocol Support.
ssl_protocols TLSv1.2;
Полный конфиг получается следующий.
server {
server_name www.example.com example.com;
listen 443 ssl default_server;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES256-SHA384;
ssl_ecdh_curve secp384r1;
add_header Strict-Transport-Security "max-age=31536000";
ssl_protocols TLSv1.2;
}
Проверим, что никакой ошибки в настройке шифров и протоколов нет.
$ nmap --script ssl-enum-ciphers -p 443 example.com
Starting Nmap 7.40 ( https://nmap.org ) at 2017-03-01 00:00 UTC
Nmap scan report for example.com (1.2.3.5)
Host is up (0.030s latency).
PORT STATE SERVICE
443/tcp open https
| ssl-enum-ciphers:
| TLSv1.2:
| ciphers:
| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp384r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp384r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (secp384r1) - A
| compressors:
| NULL
| cipher preference: server
|_ least strength: A
Nmap done: 1 IP address (1 host up) scanned in 3.22 seconds
Шифры на месте, хоть и не в том порядке. Но это ожидаемо. Можно запускать тест.
Оценка пять с плюсом. Счастье, радость. Казалось бы.
Недостатки
Но есть одна проблема. Если результаты теста прокрутить до раздела Handshake Simulation, то мы увидим что на наш сайт не попадут пользователи IE любых версий младше 11, Java до SE 8, Android до версии 4.3 и даже некоторые версии Safari. Про софт, собранный с OpenSSL версии млаше 0.9.8, даже и не говорю.
Есть и ещё одна проблема: производительность. Наш ключ на 4096 бит непосредственно влияет на скорость установки соединения, при этом не слишком усиливает защиту. Шифры на 256 бит тоже не помогают ускорить соединеие, что касается мобильных устройств с маломощными процессорами и прочих клиентов без AES-NI (аппаратного ускорения).
В случае RSA легко убедиться в негативном влиянии на скорость, используя встроенный в OpenSSL тест.
openssl speed rsa2048 rsa4096
На маломощном Celeron 1007U разница очевидна.
sign verify sign/s verify/s
rsa 2048 bits 0.002381s 0.000071s 420.0 14051.0
rsa 4096 bits 0.016790s 0.000260s 59.6 3852.8
Подпись на стороне сервера делается в семь раз медленнее. Проверка подписи на клиенте — в 3.6 раза медленнее. На другом железе тенденция остаётся та же. Этот проигрыш в скорости — плата за усиление стойкости шифра на какие-то 16%.
Аналогичным образом проверим скорость рекомендуемых шифров на OpenSSL 1.1.0e.
for cipher in aes-128-gcm aes-256-gcm chacha20-poly1305
do openssl speed -decrypt -evp $cipher 2>/dev/null | grep ^$cipher
done | column -t
На Celeron 1007U шифр ChaCha20/Poly1305 будет в два раза быстрее AES-128, а последний на треть быстрее AES-256. На Core i7 с AES-NI картина другая: ChaCha20/Poly1305 будет медленнее AES-128 на треть, а AES-256 лишь немного медленнее AES-128. При шифровании картина примерно та же.
Обмен ключами с используемой по умолчанию кривой prime256v1
(она же secp256r1
или NIST P-256) будет существенно быстрее, чем с усиленной кривой secp384r1
(NIST P-384).
$ openssl speed ecdsap256 ecdsap384 ecdhp256 ecdhp384
sign verify sign/s verify/s
256 bit ecdsa (nistp256) 0.0001s 0.0003s 7923.8 3214.4
384 bit ecdsa (nistp384) 0.0006s 0.0023s 1756.6 430.1
op op/s
256 bit ecdh (nistp256) 0.0002s 4893.5
384 bit ecdh (nistp384) 0.0019s 525.9
Работа с P-384 требует в 7-9 раз больше времени в зависимости от операции.
Если сравнить ECDSA и RSA, то видно что в случае ECDSA вычислительная нагрузка ложится больше на клиента, чем на сервер.
Если вы захотите повторить тесты у себя, то перед тестами стоит поднять приоритет текущего процесса.
sudo renice -1 $$
Очевидно одно: к выбору шифров и параметров нужно подходить более взвешено.
Принцип поиска шифров
Перечисление шифров списком — не лучшая идея потому что уже скоро можно будет штатно, без перекомпиляции и сторонних источников, использовать ChaCha20/Poly1305 в nginx. С явным заданием шифров сервер не будет использовать любые новые виды шифрования без перенастройки. Это не то, о чем вы хотите думать каждый день.
Будет лучше выбирать шифры по ключевым словам или тегам, каждое из которых соответствуют какой-то группе шифров. Ключевые слова в разных версиях OpenSSL отличаются, но мы всегда можем их проверить.
Например, тег EECDH соответствует всем шифрам с обменом одноразовыми (эфемерными) ключами по алгориму DH с эллиптическими кривыми.
$ openssl ciphers -v 'EECDH' | column -t
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1
ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256
ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1
ECDHE-ECDSA-AES128-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1
ECDHE-RSA-RC4-SHA SSLv3 Kx=ECDH Au=RSA Enc=RC4(128) Mac=SHA1
ECDHE-ECDSA-RC4-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=RC4(128) Mac=SHA1
ECDHE-RSA-DES-CBC3-SHA SSLv3 Kx=ECDH Au=RSA Enc=3DES(168) Mac=SHA1
ECDHE-ECDSA-DES-CBC3-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=3DES(168) Mac=SHA1
ECDHE-RSA-NULL-SHA SSLv3 Kx=ECDH Au=RSA Enc=None Mac=SHA1
ECDHE-ECDSA-NULL-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=None Mac=SHA1
Шифры показываются в списке согласно приоритету: клиент выберет первый подходщящий шифр, просматривая список в указанном порядке.
Если бы у нас была самая последняя версия OpenSSL, то для получения того же списка мы бы использовали понятный тег ECDHE, дающий тот же самый список и соответствующий префиксу шифров. В текущей версии такого тега нет, потому используем какой есть.
В полученном списке бросаются в глаза шифры без, собственно, шифрования, которые идут с отметкой Enc=None
. Исключим такие шифры, дающие только аутентификацию. Заодно исключим шифры без аутентификации.
openssl ciphers -v 'EECDH:!aNULL:!eNULL'
Для полного и безвозратного исключения теги групп aNULL и eNULL c неподходящими шифрами упомянуты с отрицанием. В списке не останется шифров с Au=None
или с Enc=None
.
Теги можно сочетать, получая пересечения множеств шифров. Получим шифры, сочетающие ECDHE, AES-256 и GCM.
$ openssl ciphers -v 'EECDH+AES256+AESGCM' | column -t
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
Группы шифров можно переместить ниже по приоритету, указав с плюсом в начале. Понизим приоритет у шифров с AES-256, не удаляя их.
$ openssl ciphers -v 'EECDH+aRSA+AES:+AES256' | column -t
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256
ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1
Можно временно убрать какую-то группу шифров, чтобы потом добавить её в другом виде. Исключим из всех ECDHE шифров шифры с 3DES, а затем вернём их обратно, но только в сочетании с обменом ключами RSA. Такие слабые шифры должны оказаться в самом конце списка.
$ openssl ciphers -v 'EECDH:-3DES:RSA+3DES' | tail -1 | column -t
DES-CBC3-SHA SSLv3 Kx=RSA Au=RSA Enc=3DES(168) Mac=SHA1
Выбираем шифры
Теперь у нас есть всё, чтобы составить список шифров для nginx, которые не будет требовать дополнения при выходе новых версий OpenSSL, теряя старые шифры и приобретая новые без какого-либо участия с нашей стороны. Мы учём необходимость поддержки старых браузеров и требования к скорости.
Начнём с получения уже используемого нам списка шифров, но не будем исключать шифры для сертификатов c EC на случай если мы когда-нибудь захотим использовать такой вид сертификатов.
$ openssl ciphers -v 'EECDH+AES256' | column -t
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1
ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1
На деле нам нужнен не столько конкретно AES, а сколько не нужны слабые шифры 3DES и RC4. Последний исключим полностью и навсегда.
$ openssl ciphers -v 'EECDH:-3DES:!NULL:!RC4' | column -t
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1
ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256
ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1
ECDHE-ECDSA-AES128-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1
Отдадим приоритет более быстрым шифрам, понизив его для AES-256. Совсем удалять AES-256 не будем на случай если кому-то очень будет нужен именно AES-256. (Добавочные биты у него — воображаемые.)
$ openssl ciphers -v 'EECDH:+AES256:-3DES:!NULL:!RC4' | column -t
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256
ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1
ECDHE-ECDSA-AES128-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1
ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1
Такая строка шифров не исключит ChaCha20/Poly1305 в следующей версии OpenSSL.
$ openssl version; openssl ciphers -v 'EECDH:+AES256:-3DES:!NULL:!RC4' | column -t | head -n 6
OpenSSL 1.1.0e 16 Feb 2017
ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=RSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-CCM8 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESCCM8(128) Mac=AEAD
ECDHE-ECDSA-AES128-CCM TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESCCM(128) Mac=AEAD
Для некоторых устаревших клиентов вернём AES без эфемерных ключей.
$ openssl ciphers -v 'EECDH:+AES256:-3DES:RSA+AES:!NULL:!RC4' | column -t
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256
ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1
ECDHE-ECDSA-AES128-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1
ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1
AES256-GCM-SHA384 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(256) Mac=AEAD
AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256
AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1
AES128-GCM-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(128) Mac=AEAD
AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256
AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1
Наконец, вернём 3DES без эфемерных ключей чисто для IE8/XP. Помочь IE6/XP никак нельзя — он по умолчанию не поддерживает TLS.
$ openssl ciphers -v 'EECDH:+AES256:-3DES:RSA+AES:RSA+3DES:!NULL:!RC4' | column -t
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256
ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1
ECDHE-ECDSA-AES128-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1
ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1
AES256-GCM-SHA384 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(256) Mac=AEAD
AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256
AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1
AES128-GCM-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(128) Mac=AEAD
AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256
AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1
DES-CBC3-SHA SSLv3 Kx=RSA Au=RSA Enc=3DES(168) Mac=SHA1
Итого
С шифрами закончили. Для поддержки старых клиентов нам нужно вернуть младшие версии TLS и, для скорости, использовать обычную кривую и сертификат на 2048 бит.
server {
server_name www.example.com example.com;
listen 443 ssl default_server;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
add_header Strict-Transport-Security "max-age=31536000";
ssl_ciphers EECDH:+AES256:-3DES:RSA+AES:RSA+3DES:!NULL:!RC4;
}
С таким конфигом мы получаем ровно такой результат как у Google на начало 2017 года.
При этом мы точно знаем что у всех клиентов сайт открывается настолько быстро, насколько это возможно без использования слабых шифров: все современные браузеры используют ECDHE.
Также вам обязательно нужно настроить OCSP stapling и, опционально, кеш TLS сессий.
Автор: Алексей