Настройка SSL в Nginx

0
136

Ранее я уже описывал процесс установки сертификата StartSSL и приводил пример минимального набора параметров необходимого для использования SSL в Nginx. В этой статье речь пойдет о более тонкой настройке. Сайт, настроенный по рекомендациям в данной статье, проходит проверку SSL на А+.

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

Настройку SSL в Nginx лучше начинать с минимальных рабочих параметров:

server {
    listen 443 ssl;
    server_name domain.net;

    ssl_certificate /etc/nginx/ssl/domain_com/domain.pem;
    ssl_certificate_key /etc/nginx/ssl/domain_com/domain.key;

    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
    }
}

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

Указываем путь к файлу содержащему “связку” из сертификатов: к сертификату сервера мы присоединяем промежуточный сертификат. Важно соблюдать правильную последовательность, иначе во время запуска Nginx вы получите ошибку.

# cat ssl.crt sub.class1.server.ca.pem > domain.pem
ssl_certificate /etc/nginx/ssl/domain.pem;

Необходимо расшифровать приватный ключ и указать путь к его файлу:

# openssl rsa -in ssl.key -out private.key;
ssl_certificate_key /etc/nginx/ssl/domain.key;

Перезапустим Nginx, если все работает правильно, можно переходить к дальнейшим настройкам.

Для использования набора шифров DHE, необходимо создать ключ Диффи-Хеллмана и указывать путь к файлу в настройка Nginx:

# openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048
ssl_dhparam /etc/nginx/ssl/dhparam.pem;

С включенным SSL сервер использует дополнительные ресурсы процессора. Для снижения количества операций необходимо задать размер кэша и время хранения SSL-сессий. В 1 мегабайт кэша помещается около 4000 сессий.

ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;

Дополнительно для снижения нагрузки, мы обрабатываем сразу несколько запросов в рамках одного keepalive-соединения:

keepalive_timeout 70;

Указываем поддерживаемые сервером протоколы SSL:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

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

ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DES";

Для уменьшая время загрузки страниц, разрешаем серверу для валидации сертификата прикреплять OCSP-ответы. Для работы функции необходимо указать путь к файлу сертификата издателя и DNS-сервер.

ssl_stapling on;
ssl_trusted_certificate /etc/nginx/ssl/ca.pem;
resolver 8.8.8.8;

Что бы указать браузеру, что сайт доступен только по HTTPS, необходимо указать заголовок:

add_header Strict-Transport-Security max-age=31536000 always;

Заголовок запрещает браузеру показывать сайт в фрейме:

add_header X-Frame-Options DENY;

Чтобы предотвратить MITM атаки с поддельными сертификатами, указываем заголовок Public-Key-Pins:

add_header Public-Key-Pins 'pin-sha256="base64+info1="; max-age=31536000' always;

Для директивы pin-sha256 используем одну из команд ниже:

openssl rsa  -in domain.key -outform der -pubout | openssl dgst -sha256 -binary | base64
openssl req  -in domain.csr -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | base64
openssl x509 -in domain.crt -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | base64

Указываем браузеру что бы он использовал отданный сервером Сontent-type, вместо автоматического его определения:

add_header X-Content-Type-Options nosniff;

Заголовок активирует XSS-защиту:

add_header X-XSS-Protection "1; mode=block";

Используем переадресацию на защищенное соединение:

server {
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;

        server_name domain.net;
        return 301 https://domain.com;
}
к содержанию ↑

1. Как создать сертификат?

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

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout
/etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt

На экране вы увидите несколько вопросов. Из компонентов команды можно выделить:

  • • Openssl – это базовый инструмент командной строки. Он нужен для создания и управления сертификатами, а также файлами OpenSSL и ключами;
  • • Подкоманда req показывает, что требуется запрос для подписи сертификата X.509 (CSR). Это стандарт инфраструктуры для открытых ключей, для управления сертификатами;
  • • Опция –x509 способна вносить поправки в предыдущую команду. Они сообщает о том, что нужно создать самоподписанный сертификат вместо запроса на его подпись;
  • • -nodes служит для пропуска опции защиты SSL-сертификата с помощью пароля. Это необходимо для тог, чтобы Nginx при запуске считывал файл без необходимости вмешательства пользователя. Если поставить пароль – его нужно будет вводить после каждой перезагрузки;
  • • Опция -days365 поможет задать срок действия сертификата;
  • • Параметр -newkey rsa:2048 дает возможность сделать одновременно сертификат и ключ, ведь он не был создан ранее. Число 2048 значит, что ключ будет на 2048 бит;
  • • Строка -keyout показывает, куда OpenSSL переместит полученный файл ключа;
  • • Опция -out делает то же самое, но для сертификата.

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

Строка common name очень важна. В нее нужно написать свое имя или полное доменное имя вашего сервера. Простыми словами: она нужна для связи с сервером доменного имени. Если его нет, укажите IР сервера. Поля будут выглядеть как-то так:

Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:New York
Locality Name (eg, city) []:New York City
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Bouncy Castles, Inc.
Organizational Unit Name (eg, section) []:Ministry of Water Slides
Common Name (e.g. server FQDN or YOUR name) []:server_IP_address
Email Address []:[email protected]_domain.com

Обратите внимание, что файлы сертификата и ключа будут перемещены в папку /etc/nginx/ssl. Если применять OpenSSL, вам предстоит также сделать специальные ключи Диффи-Хеллмана для поддержки PFS. Чтобы это сделать, наберите в командной строке:

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Подождите несколько минут пока сгенерируются ключи. Они будут размещены в каталоге /etc/ssl/certs/dhparam.pem.

к содержанию ↑

2. Как настроить Nginx для поддержки SSL-сертификатов?

Созданные нами ключи хранятся в папке: /etc/ssl. Теперь нам нужно будет внести правки в настройки веб-сервера Nginx:

1) В первую очередь – создать сниппет, показывающий папку, в которой хранятся SSL и ключ. Новый сниппет для Nginx создаем в папке /etc/nginx/snippets. Мы советуем вам отразить его назначение в названии. Наберите в консоли:

sudo nano /etc/nginx/snippets/self-signed.conf

В файл добавим правило ssl_sertificate, указывающее путь к нашему сертификату. Кроме того, нам потребуется директива ssl_sertificate_key для пути к ключу:

ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;

2) Теперь потребуется добавить настройки сертификата с помощью еще одного сниппета. Это позволит нам получить надежный механизм шифрования с помощью дополнительных возможностей безопасности. Заданные параметры получится применять в будущих конфигурациях веб-сервера Nginx. Дайте файлу какое-нибудь общее имя:

sudo nano /etc/nginx/snippets/ssl-params.conf

Настроим DNS-распознаватель для запросов с восходящего канала, а также добавим ssl_dhparam для поддержки ключей Диффи-Хеллмана. Получится вот так:

# from https://cipherli.st/
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
ssl_dhparam /etc/ssl/certs/dhparam.pem;

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

3) И последнее: настроить блоки server, чтобы они могли обслуживать запросы SSL и поддерживать новые настройки. В нашей статье рассматривается случай применения виртуального хоста default (блок server). Он хранится в папке /etc/nginx/sites-available. Если захотите пользоваться другим файлом, нужно указать его имя. Создадим резервную копию файла блока server с помощью:

sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak

Теперь этот блок откроем в редакторе:

sudo nano /etc/nginx/sites-available/default

Он будет выглядеть где-то так:

server {
listen 80 default_server;
listen [::]:80 default_server;
# SSL configuration
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
. . .

Перенаправим незашифрованные HTTP-запросы на HTTPS. Если же вам требуется поддержка двух протоколов, то мы такой случай рассмотрим позже. Делим настройки на два отдельных блока. Правило server_name будет идти после двух директив listen. В нем требуется указать IP-адрес либо доменное имя. Ну, а на второй блок server настроим переадресацию. Имейте ввиду, что для настройки мы будем использовать временный редирект 302. Когда настройки будут правильные, можете смело задавать постоянный редирект 301. В файл добавим:

server {
listen 80 default_server;
listen [::]:80 default_server;
server_name server_domain_or_IP;
return 302 https://$server_name$request_uri;
}
# SSL configuration
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
. . .

После этих строк нам предстоит добавить новый блок server для оставшихся настроек. Правило listen, использующее порт 443, нужно раскомментировать. Потом напишем правило http2 поддерживающее HTTP/2. Созданные ранее сниппеты нужно теперь просто выключить в файл. Помните, что в файле может существовать только одно правило listen, для комбинаций портов и IP-адресов, включающая модификатор default_server. Его нужно оставить только в одном блоке и удалить из остальных.

server {
listen 80 default_server;
listen [::]:80 default_server;
server_name server_domain_or_IP;
return 302 https://$server_name$request_uri;
}
server {
# SSL configuration
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
include snippets/self-signed.conf;
include snippets/ssl-params.conf;
. . . 

Изменения нужно сохранить, а файл – закрыть. Если нужно настроить одновременную поддержку HTTP и HTTPS, то объедините два блока server в один. Редирект же нужно удалить.

server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name server_domain_or_IP;
include snippets/self-signed.conf;
include snippets/ssl-params.conf;
. . .

Эти изменения нужно сохранить. После этого закрывайте файл.

к содержанию ↑

3. Как настроить брандмауэр?

Мы будем настраивать брандмауэр ufw для поддержки SSL-трафика. При инсталляции Nginx проводит регистрацию нескольких профилей в ufw. Вы можете просмотреть доступные с помощью команд:

sudo ufw app list
Available applications:
Nginx Full
Nginx HTTP
Nginx HTTPS
OpenSSH

Нам также нужно будет увидеть текущие настройки брандмауэра. Наберите в консоли:

sudo ufw status

Они будут выглядеть вот так, если поддерживается только трафик с протокола HTTP:

Status: active
To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
Nginx HTTP                 ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Nginx HTTP (v6)            ALLOW       Anywhere (v6)

Нам же нужна поддержка и HTTPS. Для этого мы отключим профиль Nginx HTTP и настроим Nginx Full. Наберите в командной строке:

sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'

Настройки брандмауэра изменятся и будут выглядеть вот так:

sudo ufw status
Status: active
To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
Nginx Full                 ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Nginx Full (v6)            ALLOW       Anywhere (v6)
к содержанию ↑

4. Как обновить настройки Nginx

После корректировки настроек веб-сервера и брандмауэра нужно перезапустить Nginx, чтобы все изменения вступили в силу. Проверьте синтаксис на наличие ошибок с помощью:

sudo nginx -t

Если все правильно, на экране вы увидите:

nginx: [warn] "ssl_stapling" ignored, issuer certificate not found
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

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

sudo systemctl restart nginx
к содержанию ↑

5. Тестируем настройки

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

https://домен_или_IP_сервера

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

Your connection is not private
Attackers might be trying to steal your information
(for example, passwords,messages, or credit cards). NET::ERR_CERT_AUTHORITY_INVALID

Браузер не может проверить подлинность хоста, поэтому и выдает такое сообщение. Но нам нужно лишь шифрование соединения, которое сертификат нормально обеспечивает. Можно просто пропустить данное сообщение безопасности, нажав кнопку «Advanced», а также кликнув по показанной ссылке. Это даст вам доступ к вашему сайту. Нам нужно будет также проверить, работает ли переадресация трафика с HTTP на HTTPS, если ранее настраивали два блока server:

http://server_domain_or_IP
к содержанию ↑

6. Как сделать постоянный редирект?

Если работа всех настроек сервера правильная, можно вместо временного редиректа ставить постоянный. Для этого откроем файл блока server:

sudo nano /etc/nginx/sites-available/default

В нем нужно найти return 302 и заменить значение на 301. Получится следующее:

server {
listen 80 default_server;
listen [::]:80 default_server;
server_name server_domain_or_IP;
return 301 https://$server_name$request_uri;
}
. . .

Изменения в файле нужно сохранить и закрыть его. Не забудьте проверить синтаксис на предмет содержания ошибок. Для это потребуется команда:

sudo nginx -t

Если все правильно, Nginx можно перезапустить с помощью:

sudo systemctl restart nginx

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

Оставьте свой ответ