Перевод Nginx на HTTPS.

nginx https ssl

Доброго времени суток читатели и гости моего блога. В данной статье я буду продолжать рассказ о переводе своего сайта на использование HTTPS-протокола с поддержкой SSL-шифрования. В предыдущей статье я рассказал о способах получения SSL-сертификатов, а в этой речь пойдет о переводе Nginx под HTTPS. Заодно прикрутим поддержку протокола HTTP/2.

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

Поскольку HTTPS использует 443 TCP порт, то его нужно указать в конфиге. Помимо порта нужно добавить параметр "ssl", указывающий что все соединения на данном порту должны работать в SSL-режиме.

Обычно параметр "ssl" указывают когда сервер работает в двух режимах HTTP и HTTPS одновременно. Раньше в Nginx SSL-режим можно было включать только для всего сервера, а настроить выборочно было нельзя. Поэтому в версии 0.7.14 был добавлен параметр "ssl" для директивы lis­ten, который позволил сделать единый сервер для HTTP/HTTPS сайтов. Но поскольку я хочу прикрутить еще и поддержку HTTP/2-соединений, то параметр ssl должен быть указан.

После изменения порта в конфиге, убедитесь что 443 порт открыт для приема соединений. В Netfilter/Iptables это можно сделать следующим правилом.

Что касается поддержки HTTP/2 протокола, то тут все просто, надо всего лишь добавить "http2" в значение директивы lis­ten.

Ключи и сертификаты

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

Создадим каталог для их хранения и поместим файлы в него.

Указываем серверу где искать файл сертификата и ключ.

Продолжительность сессии и тип кэша

Задаем продолжительность сессии ssl_session_timeout, в течении которой можно повторно использовать установленные параметры соединения. Помимо продолжительности зададим тип и размер кэша хранения параметров сессий ssl_session_cache.

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

Ключ Диффи — Хеллмана для DHE-шифров

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

Обмен ключом происходит только один раз, во время установки соединения. Когда клиент и сервер "договорились" о секретном ключе, то дальнейший обмен будет происходить при помощи SSL-шифрования без лишних подтверждений. Стороны обмениваются зашифрованными данными, шифруя и дешифруя сообщения общим секретным ключом.

Cоздаем ключ Диффи -Хеллмана. Длина ключа будет 2048-bit.

Включаем DH-ключ в конфигурацию.

Используемые протоколы

Употребление термина SSL-шифрование является неправильным, его скорее употребляют по привычке, а на деле, в настоящее время все работает на протоколе TLS.

Последняя версия протокола SSL 3.0 вышла в далеком 1996 году, она же послужила основой для создания протокола TLS 1.0. В 2014 году было заявлено о уязвимости протокола SSL 3.0. И с тех пор все потихоньку перебрались на использование TLS протоколов.

Поэтому в значениях директивы ssl_protocols у меня указаны версии протоколов TLS.

Наборы шифров

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

Я сделал проще и воспользовался онлайн генератором от Mozil­la. Уж кто-кто, а эти товарищи знают толк в извращениях в ssl-конфигурации. Обратите внимание что для поддержки шифров CHACHA20, Nginx должен быть собран с поддерживающей данный шифр версией Openssl.

Директивой ssl_prefer_server_ciphers задаем приоритет серверных шифров. Тем самым указывая клиентам что нужно использовать шифры сервера.

HSTSHTTP Strict Transport Security

HSTS (HTTP Strict Trans­port Secu­ri­ty) — это механизм защиты от даунгрейд-атак на TLS, он указывает браузеру что для данного сайта всегда нужно использовать TLS. Подобное указание следует из HTTP-заголовка Strict-Trans­port-Secu­ri­ty когда клиент первый раз посещает сайт и имеет определенный срок действия.

Прикрепление OCSP-ответов

Разрешим серверу прикреплять OCSP-ответы (Online Cer­tifi­cate Sta­tus Pro­to­col - Протокол проверки статуса SSL-сертификата). Обычно подтверждение сертификата происходит следующим образом. Браузер получает сертификат от сайта и просматривает его серийный номер, после чего обращается к серверам-ответчикам УЦ (Удостоверяющий Центр) чтобы проверить действительность сертификата по полученному серийнику. Иногда браузер может и не получить ответ, потому что ответчики некоторых УЦ работают ненадежно.

Включенный OCSP Sta­pling решает эту проблему. Ответ OCSP уже содержит электронную подпись, браузеру ведь все равно как она получена, главное чтобы она была действительна. Подпись передается во время установки соединения и действует некоторое время после установки. А сам веб-сервер постоянно связывается с УЦ и обновляет сведения о сертификате, которые потом отдает своим клиентам.

Почти все современные браузеры поддерживают OCSP, кроме CHROME, в нем проверку убрали. Так что смотрите сами, нужна вам эта опция или нет, говорят что при включенных ответах страницы быстрее грузятся, но как мне кажется, человек разницы все равно не увидит.

Прикрепление OCSP-ответов включается директивой ssl_stapling. Чтобы OCSP-ответы работали, дополнительно указывают DNS-сервер директивой resolver. В resolver'е нужно указать ip-адреса DNS-серверов, например публичные DNS Google - 8.8.8.8 и 8.8.4.4, адреса указываются через пробел, не обязательно указывать несколько адресов, можно указать один. Параметр valid является необязательным, он указывает серверу на какой промежуток времени нужно закэшировать полученный ответ.

Узнать OCSP-ответ сервера можно следующей командой.

Ответом будет подобный вывод, если ничего нет, то OCSP-ответы не поддерживаются.

Редирект на HTTPS

Для клиентов использующих старые ссылки для доступа на ваш сайт, необходимо прописать редирект на HTTPS, чтобы человек пришедший по старому адресу http://test.com был перенаправлен на https://test.com.

Теперь все ломящиеся на 80-й порт будут отправлены на 443-й.

Запрет доступа по ip-адресу при использовании HTTPS

Если нужно запретить доступ по ip-адресу при использовании HTTPS, то можно воспользоваться следующей конструкцией.

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

При вводе адреса http://93.170.169.118/ сервер как и положено, разрывал соединение с клиентом, но после перевода сайта на HTTPS нужно было закрыть лазейку и на 443 порту. Потому что при переходе по адресу https://93.170.169.118/ открывался мой сайт, что было не очень хорошо.

Здраво рассудив что вышеуказанная конструкция закрывающая доступ на 80-м порту, должна также работать и для 443-го, я применил ее особо не задумываясь, просто поменяв номер порта.

Как оказалось я был прав лишь отчасти. Конструкция работала, при попытке перейти по адресу вида https://93.170.169.118/, сервер разрывал соединение и все было бы хорошо, если бы не одна досадная деталь, сервер разрывал соединение и при попытке перейти по адресу вида https://techlist.top. Говоря другими словами на сайт стало нереально попасть, то есть вообще никак.

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

Делаем самоподписанный сертификат. Сначала ключ.

Потом CSR-запрос.
Собственно сам сертификат.

В итоге мы получили три файла: server.crt, server.csr, server.key, из них нас интересует только два - server.crt и server.key. Скопируем их в каталог /etc/nginx/ssl.

Вот так выглядел промежуточный вариант запрета доступа по ip-адресу через https.

При попытке перейти по адресу https://93.170.169.118/, браузер сначала ругался на сертификат, а если продолжить, то сервер разрывал соединение и страница была недоступна. Но обращение по доменному имени работало и я посчитал задачу выполненной.

Но я опять был частично неправ. В дальнейшем, во время онлайн-тестов по проверке SSL, стали вылезать разные косяки, то не работали OCSP-ответы, то не поддерживался кэш сессий. Опытным путем я нашел как устранить эти неполадки, нужно было просто добавить опции отвечающие за кэш сессий и OCSP.

В итоге конечный вариант запрета доступа по ip-адресу через https стал выглядеть так.

На самом деле это практически и не нужно. Очень редко кто использует адрес вида https://xx.xx.xx.xx, ведь если вбить ip-адрес в адресную сроку браузера, а потом скопировать его, то можно увидеть что он будет вида http://xx.xx.xx.xx а не https://. Но на всякий случай я решил закрыть эту возможность.

Куда все это писать?

Вся конфигурация отвечающая за SSL, должна находиться в контексте serv­er {} вашего хост-файла.

В одной из предыдущих статей по настройке и конфигурации Nginx, я рассказывал как у меня все организовано. Поэтому мне нужно просто подключить файл с SSL-конфигурацией в контекст serv­er {} своего хост-файла. Например, вот так.

А вот и сам файл ssl.conf находящийся в /etc/nginx/conf.

Если вы прописываете все в одном файле, то можно добавить данный конфиг в контекст serv­er {}, сразу после указания корневой директории сайта и лог-файлов.

Например так.

Результат моего труда и оценку можно посмотреть тут, заодно и проверить свои успехи.