SSL-аудит nginx после Heartbleed: от B до A минимальными правками
Прогнали клиентские nginx-серверы через ssllabs.com - большинство получили B из-за TLSv1.0 и слабых шифров. Разбираем минимальный набор директив для оценки A.
После Heartbleed в апреле 2014 сообщество продолжает аудит SSL/TLS-конфигураций веб-серверов; в рамках аудита клиентских серверов большинство nginx-инстансов получили оценку B из-за включённого TLSv1.0 и слабых шифров
После Heartbleed в апреле всем стало чуть неловко за то, как давно они последний раз смотрели на SSL-конфигурацию своих серверов. Мы не исключение. Поводом для систематического прохода по клиентским серверам стала просьба одного из клиентов - он прочитал про уязвимость, обновил OpenSSL, и на этом остановился. Мы договорились сделать полный аудит безопасности - и заодно прогнали через него всех остальных.
Инструмент - ssllabs.com/ssltest. Бесплатный, публичный, даёт подробный разбор: протоколы, шифры, цепочка сертификатов, forward secrecy, уязвимости. На выходе оценка от A+ до F. Ожидали разброс - получили унылое однообразие: большинство серверов дали B.
Почему B, а не хуже
Оценка B - это не катастрофа, но сигнал. У Qualys чёткая логика: B значит, что конфигурация в целом нормальная, но есть что-то, что тянет вниз. В нашем случае везде было одно и то же:
- TLSv1.0 включён - протокол 1999 года, к которому уже есть атаки (BEAST, в частности). Qualys снижает оценку за его поддержку.
- Слабые шифры в наборе - RC4 и шифры без PFS (perfect forward secrecy). RC4 в 2014 году всё ещё часто встречается в дефолтных nginx-конфигах, но атаки на него накопились.
- Цепочка сертификатов не передаётся полностью - браузеры справляются, но это замечание и потеря баллов.
Всё это наследие того, что конфигурации ставились давно по документации «лишь бы работал HTTPS», и никто их не трогал.
Минимальный набор директив
Минимальные изменения, которые поднимают оценку с B до A на большинстве серверов с nginx 1.4-1.6:
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
Плюс для ECDHE нужен DH-параметр - без него Diffie-Hellman работает на дефолтных 1024-битных параметрах, что тоже тянет оценку вниз:
openssl dhparam -out /etc/nginx/dhparam.pem 2048
И в конфиг:
ssl_dhparam /etc/nginx/dhparam.pem;
Генерация 2048-битного dhparam занимает несколько минут - нормально, это разовая операция.
Что решили не включать
HSTS (add_header Strict-Transport-Security) - не добавляли по умолчанию. Причина простая: если сертификат истечёт или сломается переход на HTTPS - сайт станет недоступен для браузера без ручного вмешательства пользователя. Для клиентов, где HTTPS обязателен и процедура обновления сертификатов отлажена - добавили. Там, где HTTP и HTTPS работают параллельно или бывают тестовые домены - не стали рисковать.
OCSP Stapling (ssl_stapling on) - включили тем, у кого правильно передаётся цепочка сертификатов. Это ускоряет TLS-рукопожатие и убирает замечание от ssllabs, но требует, чтобы nginx мог достучаться до OCSP-сервера удостоверяющего центра. На серверах с файрволом, режущим исходящие соединения, проверяем отдельно.
Совместимость
Исключение TLSv1.0 ломает поддержку IE6 на Windows XP. В 2014 году это звучит как не очень страшно, но на практике у нескольких клиентов доля XP в аналитике была ненулевой. Проверяли заранее - для двух клиентов отложили отключение TLSv1.0 до согласования с ними.
RC4 используется некоторыми старыми Android-устройствами (2.x) как запасной шифр. При наличии ECDHE и AES-GCM в наборе устройства с Android 4+ подключаются нормально. Android 2.x при таком наборе может упасть. Опять же - смотрели на аналитику.
Итог прохода
После правок все серверы, где не было явных ограничений по совместимости, получили A. Несколько серверов остались на B - это осознанное решение по согласованию с клиентами, а не просчёт. Разница между «мы не проверяли» и «мы проверили и решили не менять» - принципиальная.
Конфигурация шифров выше основана на рекомендациях Mozilla Server Side TLS Guide - публичный документ, который регулярно обновляется и объясняет логику каждого шифра. Рекомендуем держать его в закладках и сверяться при обновлении nginx или смене сертификатного центра.
Один нюанс, который вылез в процессе: ssllabs кеширует результаты несколько часов. После изменения конфига - перезапуска nginx недостаточно, нужно подождать или добавить &startNew=on к URL теста. Потратили на это чуть больше времени, чем следовало.