NGINX и SSL: Поддержка ChaCha20-Poly1305 с приоритетом устройствам без AES-NI

Эту небольшую заметку можно назвать продолжением моей первой статьи о том, как же получить A+ на SSLLabs. Я продолжаю улучшать скорость и безопасности HTTPS соединения. Стоит понимать, что мой интерес носит скорее спортивный характер и моему сайту в принципе не нужна безопасность подобного уровня, но собственно почему бы и нет?

Перейдем к самому вопросу. Использовать и пересобирать мы будем Mainline-версию NGINX, на данный момент последняя версия имеет номер 1.11.6. Именно она поддерживает самый полный спектр технологий, однако при этом остается достаточно стабильной, чтобы использовать её на продакшене. К примеру корпоративные клиенты компании NGINX, использующие её NGINX Plus сейчас переходят на версию R11, которая является как раз-таки дополненной 1.11.6. Изменений относительно стабильной 1.10.2 там прилично, но самыми броскими для меня оказались:

  • Поддержка нескольких сертификатов. Например, можно использовать RSA- и ECC-сертификаты одновременно.
  • Поддержка нескольких видом элиптических кривых одновременно. К примеру, если клиент не поддерживает secp521r1, то сервер сможет спустится на secp384r1 или prime256v1.

Однако об этом мы поговорим немного позже в следующих заметках.

В этой статье речь пойдет про патч от Cloudflare, который привносит поддержку ChaCha20-Poly1305-шифров. Однако в отличии от OpenSSL 1.1.0c, где поддежка этих шифров также имеется, патч от Cloudflare позволяет отдавать приоритет при выборе шифров именно устройствам без AES-NI. То есть устройствам без хардварного ускорения AES-шифрования. Таких устройств нынче мало, но они всё-таки есть и в достаточно большом номинальном количестве. К примеру это почти все Android-устройства, кроме самых новых и флагманских. Учитывая, что мобильный рынок развивается очень быстро, то выиграть несколько миллисекунд во время SSL-хэндшейка весьма приятно.

Кстати в SSLLabs это выглядит вот так

Дисклеймер: Все последующие действия выполнялись на абсолютно чистой машине на базе Debian Jessie. Не ставился даже NGINX из репозиториев.

Патчить мы будем SSL библиотеку OpenSSL, а затем с этой патченной библиотекой мы будем собирать наш новый крутой NGINX :) Первым делом ставим нужные для сборки либы и утилиты:

1
sudo apt-get install build-essential libpcre3 libpcre3-dev zlib1g-dev unzip git libgd2-dev

Скачиваем патч от Cloudflare, OpenSSL и NGINX:

1
2
3
git clone https://github.com/cloudflare/sslconfig.git
wget -O openssl.tar.gz https://github.com/openssl/openssl/archive/OpenSSL_1_0_2j.tar.gz
wget https://nginx.org/download/nginx-1.11.6.tar.gz

Распаковываем всё:

1
2
3
4
tar zxf openssl.tar.gz
mv openssl-OpenSSL_1_0_2j openssl
tar zxf nginx-1.11.6.tar.gz
mv nginx-1.11.6 nginx

Патчим OpenSSL (убедитесь, что всё прошло нормально по логу!)

1
2
3
cd openssl
patch -p1 < ../sslconfig/patches/openssl__chacha20_poly1305_draft_and_rfc_ossl102j.patch
cd ..

В директории nginx создаем новый файл custom_configure:

1
2
3
4
5
6
7
8
cd nginx
nano custom_configure
# Содержимое файла, скопируйте и сохраните (Ctrl+O) и выйдите (Ctrl+X)
./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=www-data --group=www-data --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-threads --with-stream --with-stream_ssl_module --with-http_slice_module --with-mail --with-mail_ssl_module --with-file-aio --with-http_v2_module --with-stream_realip_module --with-openssl=../openssl
# Право на выполнение новоиспеченного скрипта
sudo chmod +x custom_configure

Ключи конфигурации обыкновенные для Debian, добавлен только --with-openssl для сборки с патченной версией OpenSSL. Наконец собираем:

1
2
3
4
5
6
7
./custom_configure
# Если ошибок нет, продолжаем
make
# Ждем сборки (от двух до пятнадцать минут), устанавливаем
sudo make install

Можете уже проверить NGINX командой nginx -V. Она отобразит с какими ключами и какой версией OpenSSL nginx был собран. Однако это ещё не всё. Последним шагом будет создание systemd-службы.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
sudo nano /etc/systemd/system/nginx.service
# Копируем такое содержимое
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
# Исправляем небольшую ошибку
sudo mkdir -p /var/cache/nginx/client_temp
# Обновляем демонов
sudo systemctl daemon-reload
# Включаем службу
sudo systemctl enable nginx
sudo systemctl start nginx

Протестировать работу нового сервера можно обратившись к моему предыдущему гайду и исправив одну строку в главном конфигурационном файле nginx.conf

1
2
3
4
5
# Заменяем это
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:!AES128';
# на это
ssl_ciphers 'EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AESGCM:EECDH+AES256:EDH+AES';