в debian, nginx

Let’s Encrypt и Nginx: получаем максимум от ssllabs.com и securityheaders.io

lets-encrypt
Когда-то поддержка SSL-шифрования сервисами позиционировалась как «желательная» (nice-to-have feature), но не так давно она перешла в разряд «обязательных» (must-have). Пожалуй, переломный момент наступил когда Google начал использовать HTTPS в качестве фактора ранжирования в своей поисковой выдаче.

Однако время не стоит на месте — требования к безопасности меняются, повсеместно внедряется http2.0, разрабатываются новые алгоритмы сжатия и уже недостаточно просто подключить SSL-сертификат на сайте. Что нужно сделать чтобы получить максимальную оценку от сервисов ssllabs.com и securityheaders.io — давайте разберемся!

Примечание. Будьте внимательны и выполняйте предложенные действия на свой страх и риск.

Считаем, что:

  • у вас есть SSL-сертификат (от Let’s Encrypt или платный), о том как получить бесплатный сертификат и подключить его в Nginx читайте здесь или здесь;
  • у вас установлена версия Nginx с поддержкой http2.0;
  • желательно, чтобы ваша версия Nginx поддерживала APLN (Application-Layer Protocol Negotiation);
  • не повредит, если вы стараетесь быть «в теме» и добавили поддержку модуля ngx_brotli в Nginx.

Итак, приступим. Ранее мы договаривались для удобства настройки хранить все специфические для SSL параметры в конфигурационном файле /etc/nginx/ssl/ssl.conf и с помощью директивы include подключать эти настройки в блоках server.

Сейчас конфигурационный файл /etc/nginx/ssl/ssl.conf выглядит следующим образом:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384: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_session_timeout 1h;
ssl_session_cache shared:SSL:128m;
ssl_stapling on;
ssl_stapling_verify on;

resolver 127.0.0.1 valid=300s;
resolver_timeout 10s;

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

ssl_protocols TLSv1.2;

а параметр ssl_ciphers заменим на:

ssl_ciphers EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;

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

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

...
    add_header Strict-Transport-Security max-age=15768000;
    add_header Content-Security-Policy "default-src 'self'; script-src https: 'self' 'unsafe-inline' 'unsafe-eval'; object-src https: 'self'; style-src https: 'self' 'unsafe-inline'; connect-src https: 'self'; frame-src https:; font-src https: data:; img-src data: *;";
    add_header Public-Key-Pins 'pin-sha256="LQNaYu41ymuFBkht845oLTrkb4cPSaCIPphbJsZD8zk="; pin-sha256="SCq+r/MQCGRX6c/8OAszCPvJNITAJK//ekrlXOO7pcY="; pin-sha256="nGgctXlFLbcmoOfWZ7pQE0fB3q7GWa+FNGYkoKgkhoU="; max-age=5184000';
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Xss-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
...

Подробности и нюансы использования данных заголовков великолепно описал Scott Helme, от себя могу добавить только что самым неоднозначным и непростым в настройке из них является add_header Public-Key-Pins ... — в его правильной настройке мне помогли материалы из блогов Thomas Elsen, Henrik Lilleengen и Joschi Kuphal, а после получения максимальной оценки от securityheaders.io я временно отключил его.

После внесенных изменений перечитываем конфигурацию Nginx:

nginx -s reload

И проверяем сайт на ресурсах, указанных в начале статьи:

На securityheaders.io вполне можно получить и оценку A+, если в заголовке add_header Content-Security-Policy убрать значение 'unsafe-inline' из секции script-src, но тогда возникают проблемы с отображением рекламных баннеров на сайте.

Добавить комментарий

  1. Не смог прочитать эту статью в Chrome Version 56.0.2924.87 (64-bit) for macOS. Пришлось запускать Safari. 😉

    Хром же ругается вот как:

    NET::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN