Время чтения: 19 мин.

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

Помимо этого, HTTPS нельзя настроить один раз и «забыть». Обилие разнообразных технологий и алгоритмов шифрования появилось не от хорошей жизни: это настоящая гонка с теми, кто по разным причинам хочет слушать или вмешиваться в коммуникации. После развертывания HTTPS придется следить за актуальностью ПО и конфигурации в дальнейшем, так как постоянно находятся и исправляются уязвимости, а технологии совершенствуются.

Отказ от ответственности. Ниже приводится лишь пример конфигурации. Я не даю никаких гарантий относительно надежности и/или безопасности конфигурации.

Тем не менее данный пример основан рекомендациях таких компаний как EFF, Google, Mozilla и Qualys SSL Labs. Данная конфигурация используется на данном сайте с изменениями, не касающимися HTTPS.

Требования

Для успешного следования инструкциям вам потребуется:

  • Доступ к терминалу на сервере и доступ к изменению настроек веб-сервера. Если у вас обыкновенный «хостинг с PHP и MySQL», рекомендую обратиться в поддержку вашего хостинга, чтобы узнать, как, и возможно ли включить HTTPS.

  • Базовые навыки работы с *nix-терминалом и настройки Nginx.

  • Доверенный сертификат, который вы собираетесь использовать. В итоге у вас должно быть два файла, один из которых является приватным ключем (private key), а другой — непосредственно сертификатом (certificate). Ни в коем случае никому и никогда не показывайте свой приватный ключ.

  • Уже настроенный и работающий по обычному HTTP сайт. Базовая настройка Nginx не рассматривается в рамках этого руководства.

Если у вас нет сертификата, то вы можете получить его бесплатно от Let's Encrypt. Их утилита даже может настроить ваш веб-сервер автоматически, в этом случае можете использовать данное руководство как справочное при разборе конфигурации.

Поддержка

Конфигурация тестировалась на Nginx 1.9.11 с OpenSSL 1.0.1f на Ubuntu 14.04.3 LTS.

Для работы HTTP/2 необходим OpenSSL 1.0.2 или новее (например, доступен на Ubuntu 16.04).

Из браузеров как минимум поддерживаются Google Chrome/Firefox/Safari/Opera 12+/Internet Explorer 8+/Edge.

Устройства: Android 2.3.7, Android 4+, iOS 6+, Windows Phone 8+

Подготовка

Если ваш приватный ключ еще не расшифрован, сделайте это. Вы можете расшифровать ключ на сервере или предварительно на своем компьютере, для этого вам потребуется выполнить следующую команду и ввести пароль.

openssl rsa -in зашифрованный_ключ.key -out расшифрованный_ключ.key

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

Загрузите сертификат и (расшифрованный) ключ на свой сервер и разместите их в директории, доступной для чтения вашему веб-серверу (и желательно только ему).

Если ваш сертификат подписан промежуточным (intermediate) сертификатом, вам необходимо приклеить к своему сертификату всю цепочку, иначе сертификат будет выдавать ошибку в некоторых браузерах. Обычно удостоверяющий центр прямо говорит об этом и предлагает скачать сертификаты всей цепочки. Для Nginx их необходимо склеить, например, так:

cat your_server.crt intermediate.pem > server.crt

Let's Encrypt это делает автоматически, используйте fullchain.pem.

Скачайте и сохраните корневой сертификат доверенного центра, это потребуется для OCSP stapling. Если используется промежуточный сертификат, их также необходимо склеить вместе:

cat root.pem intermediate.pem > trusted.crt

В случае Let's Encrypt вместо этого снова используйте fullchain.pem.

Кроме того, необходимо сгенерировать dhparam и сохранить его в файл. Это необходимо для функционирования Forward Secrecy на основе алгоритма Diffie-Hellman (DHE). Длина dhparam должна быть не короче 2048 бит, короткие значения dhparam потенциально уязвимы для атак вроде недавно обнаруженного Logjam.

openssl dhparam 2048 -out dhparam.pem

Генерация может занять несколько минут.

Конфигурация

Все правила для Nginx мы будем добавлять в блок server вашей конфигурации. Первое, что нам нужно сделать, это указать Nginx слушать порт 443, так как он по умолчанию используется для HTTPS.

listen 80 443 ssl;

В данном случае одна и та же конфигурация будет использоваться как для HTTP, так и для HTTPS. При доступе по HTTP Nginx будет игнорировать SSL-директивы, которые мы добавим далее. Если вы хотите раздавать свой сайт только по HTTPS, то просто не указывайте здесь порт 80. Ниже в данной статье описано, как сделать редирект с HTTP на HTTPS.

Включаем SSL:

ssl on;    

Указываем путь к сертификату и приватному ключу:

ssl_certificate /etc/nginx/ssl/example.com/server.crt;
ssl_certificate_key /etc/nginx/ssl/example.com/server.key;

Разрешаем использовать только TLS. SSLv2 и SSLv3 устарели и содержат уязвимости. TLSv1 и TLSv1.1 тоже устарели, но ряд еще широко используемых браузеров и устройств не поддерживает TLSv1.2.

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

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

ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA ECDHE-ECDSA-DES-CBC3-SHA ECDHE-RSA-DES-CBC3-SHA AES128-GCM-SHA256 AES256-GCM-SHA384 AES128-SHA256 AES256-SHA256 AES128-SHA AES256-SHA DES-CBC3-SHA !DSS !aNULL !eNULL !EXPORT !DES !RC4 !MD5 !PSK !aECDH !EDH-DSS-DES-CBC3-SHA !EDH-RSA-DES-CBC3-SHA !KRB5-DES-CBC3-SHA";

Указываем путь к ранее сгенерированному dhparam (см. выше «Подготовка»).

ssl_dhparam /etc/nginx/ssl/dhparam.pem;

Включаем OCSP stapling, убирая с пользователей и центра сертификации нагрузку по подтверждению валидности сертификата. resolver указывает на DNS-сервер, используемый для разрешения доменного имени доверенного центра. В данном примере указан адрес Google Public DNS (8.8.8.8). Кроме того, с помощью ssl_trusted_certificate необходимо указать корневой сертификат доверенного центра, и если используется промежуточный сертификат, они должны быть склеены (см. выше «Подготовка»).

ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8;
ssl_trusted_certificate /etc/nginx/ssl/root.crt; # или trusted.crt

Так как первоначальный обмен ключами достаточно затратная операция в плане вычислительных ресурсов,следует на некоторое время кешировать сессии, чтобы без конца не повторять их. Кешируем сессию на 10 минут в хранилище на сервере размером 10 Мб. Кроме того, мы отключаем механизм тикетов, как потенциально небезопасный.

ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;

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

Рекомендуется: HTTP/2

Также настоятельно рекомендуется включить поддержку нового стандарта HTTP/2. Помимо прочего, это позволяет ускорить HTTPS в современных браузерах до уровня, недостижимого для HTTP за счет мультиплексирования. Кроме того, расширение ALPN протокола TLS позволяет клиенту отослать зашифрованный запрос сразу после обмена ключами, не дожидаясь подтверждения сервера, что уменьшает задержку между началом запроса и моментом, когда будут переданы первые данные.

Просто добавьте http2 в список значений директивы listen:

listen 443 ssl http2;

Nginx поддерживает HTTP/2 и ALPN начиная с версии 1.9 и при наличии OpenSSL не ниже 1.0.2.

Рекомендуется: HTTPS всегда

С января 2017 года Google Chrome начнет помечать HTTP-страницы как небезопасные, если они содержат поля для ввода пароля или платежных данных. Вместе с тем, даже если вы передаете по HTTPS только пароль, а с полученной кукой позволяете просматривать сайт по HTTP, то получаете абсурдную ситуацию, в которой вы заморочились внедрением HTTPS, а злоумышленник все равно может украсть сессию пользователя и личные данные, или подменить данные на страницах сайта. Решение: использовать HTTPS всегда и создать редирект с HTTP на HTTPS.

В редиректах с HTTP на HTTPS нет ничего особенного. Если вы решили, что ваш сайт должен раздаваться только по HTTPS, то для HTTP должен быть отдельный блок server с директивой вроде:

rewrite ^ https://example.com$request_uri? permanent;

Опционально: HSTS

Если все страницы вашего сайта используют HTTPS и вы не собираетесь в ближайшем будущем отказываться от него, вы можете указывать браузеру в будущем использовать только HTTPS для доступа к сайту, даже при переходе по ссылкам http:// или без указания протокола. Для этого используется HTTP-заголовок Strict-Transport-Security. Браузер должен запомнить это на указанное время, в данном случае, 15724800 секунд или 6 месяцев:

add_header Strict-Transport-Security "max-age=15724800";

Если все поддомены вашего сайта функционируют по HTTPS, вы также можете указать и это:

add_header Strict-Transport-Security "max-age=15724800; includeSubDomains";

Это позволяет уберечь пользователей от использования небезопасного соединения к вашему сайту, но — да! — только после первого посещения ими сайта через безопасное соединение. Для решения этой проблемы был придуман механизм поставки списка HSTS-сайтов вместе с браузером — HSTS Preload. С помощью специальной страницы можно отправить заявку на добавление своего сайта в такой список, но конфигурация вашего сайта должна соответствовать ряду условий, иначе сайт добавлен в список не будет.

Поддержка IPv6

Отдельным пунктом следует упомянуть поддержку IPv6, хотя это напрямую не относится к теме статьи. Есть определенная особенность при конфигурации IPv6 в Nginx и она заключается в записи директивы listen, IPv4 и IPv6 должны быть на отдельных строках:

listen 443 ssl http2;
listen [::]:443 ssl http2;

Пример полной конфигурации

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    rewrite ^ https://example.com$request_uri? permanent;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com www.example.com;
    keepalive_timeout 70;

    root /var/www/example.com/public_html;
    index index.html index.htm;

    ssl on;

    ssl_certificate /etc/nginx/ssl/example.com/server.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com/server.key;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    ssl_prefer_server_ciphers on;
    ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA ECDHE-ECDSA-DES-CBC3-SHA ECDHE-RSA-DES-CBC3-SHA AES128-GCM-SHA256 AES256-GCM-SHA384 AES128-SHA256 AES256-SHA256 AES128-SHA AES256-SHA DES-CBC3-SHA !DSS !aNULL !eNULL !EXPORT !DES !RC4 !MD5 !PSK !aECDH !EDH-DSS-DES-CBC3-SHA !EDH-RSA-DES-CBC3-SHA !KRB5-DES-CBC3-SHA";

    ssl_dhparam /etc/nginx/ssl/dhparam.pem;

    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8;
    ssl_trusted_certificate /etc/nginx/ssl/root.crt;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;

    add_header Strict-Transport-Security "max-age=15724800";

    location / {
        try_files $uri $uri/ =404;
    }
}

Смешанное содержимое (mixed content)

Почти наверняка после настройки выше при попытке открыть страницу в браузере, вместо желанного зеленого замочка вы получите предупреждение о «смешанном содержимом» и не прогрузившуюся страницу.

Чтобы избежать этого, все ссылки на картинки, стили, скрипты, счетчики, виджеты и др. должны указывать на https://. Если на странице есть форма, то ее атрибут action также должен указывать на https://.

Чтобы избежать ухода пользователя с HTTPS на простую версию сайта, а также если вы планируете сохранить доступ по обычному HTTP, используйте относительные ссылки. Для CMS вроде WordPress, Drupla и др. существуют плагины для автоматизации всего этого хозяйства.

Cookies

Если ваш работает только по HTTPS и использует куки, он должен указывать браузеру, чтобы тот посылал куки только через безопасное соединение. Для этого установка кук происходит с атрибутом Secure. Убедитесь, что сервер также посылает куки только через безопасное соединение.

Другие рекомендации и пожелания

Используйте онлайн-тестер SSL для проверки правильности конфигурации.

Существует атака BREACH, при использовании компрессии типа gzip позволяющая «угадывать» данные на странице. Увы, единственный пока способ надежно защититься от этой атаки, без изменения кода приложения — отключить данную компрессию, по крайней мере, для страниц, содержащих чувствительные данные. Остальные методы требуют изменений в коде самого приложения.

Ах да, никогда, я повторяю, никогда не делайте редиректа с HTTPS на HTTP.

Вместо заключения

Любые исправления и вопросы в комментариях приветствуются! Не стесняйтесь задавать вопросы, если вам что-то непонятно или вы хотите совета по настройке.

Я стараюсь обновлять этот пост по мере надобности.

Полезные ссылки

QR Code

Комментарии (2)

Аватар Салатец Салатец

Добрый день, подскажите куда копать, если nginx по https ничего не хочет отдавать, в логах пусто, недавно все работало и вдруг перестало.

Аватар Alex7Kom Alex7Kom

Сложно сказать, причин может быть много. Убедитесь что nginx запущен, убедитесь что логи пишутся, убедитесь что порт HTTPS (443) открыт для входящих соединений.

Темы заметок
access_time share