Правильная настройка HTTPS на Nginx

Правильная настройка HTTPS на Nginx

На сегодняшний день в HTTPS протоколе существует ряд уязвимостей, поэтому важна правильная и безопасная настройка веб-сервера. Статья рассматривает детальную настройку HTTPS протокола для сервера Nginx, методы, описанные здесь, применимы для систем, полностью базирующихся на Nginx сервере, либо использующих его как проксирующий сервер, однако основные принципы, описанные в статье, переносимы и на другие веб-сервера.

Перед началом настройки HTTPS протокола нужно обзавестись закрытым ключом и сертификатом. Подготовим место хранения для сертификата.

mkdir –p /path/to/ssl

Теперь необходимо подготовить закрытый ключ и сертификат. Часто закрытый ключ может содержать пароль для защиты, если использовать такой ключ, то каждая перезагрузка Nginx будет спрашивать пароль. Чтобы снять защиту паролем нужно выполнить команду.

openssl rsa -in /path/to/ssl/domain.com.key -out /path/to/ssl/domain.com.nopass.key

Теперь нужно подготовить сертификат, разные браузеры могут показывать предупреждение при работе с сайтом, связано это с тем, что поставщик сертификата подписал Ваш сертификат промежуточным сертификатом, который отсутствует в списках свободно распространяемых сертификатов. Для решения это проблемы, нужно объединить сертификаты в один, начиная с полученного, и заканчивая корневым. Нужно правильно расположить сертификаты, иначе можно получить ошибку.

ssl_ctx_use_privatekey_file("/path/to/ssl/domain.com.nopass.key") failed
   (ssl: error:0b080074:x509 certificate routines:
    x509_check_private_key:key values mismatch)

Причина ошибки в том, что сервер пытается использовать закрытый ключ с неверным сертификатом.
Поместим в /path/to/ssl наш закрытый ключ без пароля и собранный сертификат, настроим права доступа, сервер Nginx работает либо от имени www-data либо nginx

chown –r www-data:www-data /path/to/ssl
chmod –r 400 /path/to/ssl/

Данная настройка позволит только пользователю читать сертификат и публичный ключ.
Сертификаты подготовлены, переходим к настройке сервера Nginx. Настройка осуществляется в блоке server. Для начала включим HTTPS и укажем наши ключ и сертификат.

listen 443;
ssl on;
ssl_certificate_key /path/to/ssl/domain.com.nopass.key;
ssl_certificate /path/to/ssl/domain.com.crt;

Nginx использует PEM формат для работы с ключами и сертификатами, поэтому можно объединить сертификат и ключ в один файл, однако с точки зрения безопасности, это не стоит делать. Начиная с версии 0.7.14, можно включить HTTPS дополнительным параметром директивы
listen

listen  443 ssl;

Минимальная настройка сделана, с такими настройками на сервере уже будет работать HTTPS, теперь нужно провести детальную настройку, чтобы исключить возможность атак на HTTPS протокол.
Включим только безопасные протоколы.

ssl_protocols tlsv1 tlsv1.1 tlsv1.2;

Nginx в стандартных настройках поддерживает SSLv3 по-умолчанию, старые версии поддерживают также SSLv2, оба протокола на текущий момент небезопасны и их не рекомендовано использовать.
Обеспечение безопасности строится на безопасности сессии, для каждой сессии создаются сессионные ключи, генерация проходит с использованием разного рода алгоритмов, обмен ключами базируется на алгоритме Диффи-Хеллмана. Часть алгоритмов скомпрометирована и не рекомендуется к использованию, поэтому важно выбрать стойкие алгоритмы для защиты сессии.
Минимально рекомендованный набор алгоритмов.

ssl_ciphers "aes128+eecdh:aes128+edh";

Если существует необходимость в поддержке старых платформ, например, Windows XP, то набор алгоритмов следующий.

ssl_ciphers "ecdhe-rsa-aes256-gcm-sha384:ecdhe-rsa-aes128-gcm-sha256:dhe-rsa-aes256-gcm-sha384:dhe-rsa-aes128-gcm-sha256:ecdhe-rsa-aes256-sha384:ecdhe-rsa-aes128-sha256:ecdhe-rsa-aes256-sha:ecdhe-rsa-aes128-sha:dhe-rsa-aes256-sha256:dhe-rsa-aes128-sha256:dhe-rsa-aes256-sha:dhe-rsa-aes128-sha:ecdhe-rsa-des-cbc3-sha:edh-rsa-des-cbc3-sha:aes256-gcm-sha384:aes128-gcm-sha256:aes256-sha256:aes128-sha256:aes256-sha:aes128-sha:des-cbc3-sha:high:!anull:!enull:!export:!des:!md5:!psk:!rc4";

Далее нужно заставить использовать сервер только указанные алгоритмы.

ssl_prefer_server_ciphers on;

Алгоритм Диффи-Хеллмана обеспечивает обмен ключами для защиты сессии, в конечном итоге вырабатывается общий секрет для шифрования сообщений. Для повышения надежности генерации секретов следует самостоятельно сгенерировать параметры для работы алгоритма Диффи-Хеллмана.

cd /path/to/ssl
openssl dhparam -out dhparam.pem 4096

Задача может затянуться на несколько минут, стоит подождать, по окончании генерации, нужно задать параметры в Nginx

ssl_dhparam /path/to/ssl/dhparam.pem;

Когда клиент подключается по HTTPS, то он осуществляет проверку сертификата на отзыв. Делается это двумя путями – через список отозванных сертификатов (Certificate Revocation List) или же по протоколу Online Certificate Status Protocol (OCSP). Проблема с CRL заключается в том, что с каждым днем список может разрастаться, и загрузка данного списка может занимать все больше и больше времени. OSCP протокол же наоборот, получает информацию только по заданному сертификату и позволяет ее хранить некоторое время в кэше. Добавим эту возможность для Nginx, она доступна начиная с версии 1.3.7

ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

Если изначально сертификат не содержит корневой сертификат, то его следует добавить в настройку.

ssl_trusted_certificate /path/to/ssl/ca.crt;

Теперь будет использоваться OCSP для проверки отзыва сертификата.
Теперь нужно ограничить использование незащищенных соединений к сайту, для этого нужно добавить следующие заголовки в ответ сервера

add_header strict-transport-security max-age=63072000;
add_header x-frame-options deny;
add_header x-content-type-options nosniff;

Эти заголовки заставят браузер принудительно использовать HTTPS вместо HTTP, это решает проблему, когда сайт полностью размещен в HTTPS, но имеет ряд ссылок на HTTP, предположим, в статье размещено изображение со старой ссылкой, данные заголовки обяжут браузер загружать изображение по безопасному протоколу.
Теперь проведем небольшую оптимизацию работы сервера, использование SSL тратит больше ресурсов. Увеличим кэш для SSL-сессий

ssl_session_cache shared:ssl:10m;
ssl_session_timeout 10m;

Данные параметры могут быть вынесены в http блок настроек сервера. Изменим также настройки таймаута.

keepalive_timeout 70;

После всех настроек, мы получим что-то вроде этого.

listen 443;
ssl on;
ssl_certificate_key /path/to/ssl/domain.com.nopass,key;
ssl_certificate /path/to/ssl/domain.com.crt;
ssl_ciphers 'aes128+eecdh:aes128+edh:!anull';
ssl_prefer_server_ciphers on;
ssl_protocols tlsv1 tlsv1.1 tlsv1.2;
ssl_session_cache shared:ssl:10m;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.4.4 8.8.8.8 valid=300s;
resolver_timeout 10s;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
add_header strict-transport-security max-age=63072000;
add_header x-frame-options deny;
add_header x-content-type-options nosniff;

На одном сервер может находиться несколько доменов, соединение с сокетом по SSL проходит до того, как будет идентифицирован домен, это все приводит к проблеме, когда отправляется сертификат другого домена, Nginx будет всегда отправлять первый сертификат. Легким решением данной проблемы является выделение каждому HTTPS серверу по отдельному IP адресу, но при большом числе доменов это может быть довольно сложно. Также можно добавить в поле SubjectAltName сертификата набор доменов, размещенных на данном сервере, но размер поля ограничен. На сегодняшний день существует расширение протокола TLS для разрешения имен (Server Name Indication), оно позволяет передать имя домена на этапе подключения, и сервер способен определить подходящий сертификат. Но данная возможность поддерживается не всеми браузерами:

  • Opera 8.0;
  • MSIE 7.0 (Windows Vista и выше);
  • Firefox 2.0;
  • Chrome (Windows Vista и выше).

При настройке HTTPS важно соблюсти баланс между поддержкой необходимых систем и безопасностью.
После завершения настройки HTTPS важно настроить переход с HTTP, сделать это можно простым редиректом.

server {
        listen  80;
        server_name domain.com www.domain.com;
        return 301 https://domain.com$request_uri;
}

Теперь каждый запрос будет перенаправлен на защищенный сервер.
Для завершения настройки необходимо перезагрузить сервер. Протестировать сервер на стойкость можно с помощью сервиса https://www.ssllabs.com/ssltest/, результат должен быть следующим

2.result

Если Вам понравилась заметка, обязательно делитесь ее со своими друзьями, если же есть пожелания или замечания – сообщите о них.
Использование материалов на сторонних ресурсах, без разрешения автора, запрещено.

Автор:Jury Sosnovsky