Date

Протокол HTTPS был разработан еще в 1994 году, но до сих многие сайты общаются с миром по незащищенному протоколу HTTP, главным образом из-за того, что получение SSL сертификата достаточно нетривиальный и дорогой процесс. Но сейчас ситуация изменилась: некоммерческий проект Let's Enctypt, поддерживаемый Mozilla, Cisco, Facebook, Google и другими крупными компаниями, начал автоматизированную выдачу бесплатных SSL сертификатов на 90 дней. Не стоит пугаться столь малого периода действия - сертификаты выпускаются автоматически с помощью python-скрипта, который можно запускать на регулярной основе (например, раз в месяц).

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

  1. Вставка провайдером своей рекламы на страницы ресурса (как это делает, например, оператор WiFi сети московского метрополитена). Что более интересно, провайдер даже может заменять имеющуюся рекламу на свою.
  2. Вставка злоумышленником вредоносного кода на страницы ресурса. Особенно часто это практикуют зловреды, заражающие WiFi-роутеры: они могут как подменять определенны категории ссылок (ссылки на файлы или известные ресурсы) на фишинговые ресурсы, так и вставлять вредоностный JavaScript.

Конечно, HTTPS не панацея от всех бед, но позволяет проявить хотя бы немного заботы о своем пользователе, тем более что сейчас это не займет много времени (и совсем не потребует денег).

У проекта Let's Encrypt есть шикарная документация и плагины для автоматизированной настройки Nginx и Apache. Я же выбрал путь автоматического получения сертификата через скрипт, запущенный в отдельном docker-контейнере, и ручную настройку Nginx. Все действия производились на Ubuntu 14.04.

Установка Docker

Первом делом нужно установить Docker (если он еще не был установлен).

sudo apt-get install linux-image-extra-`uname -r`
sudo echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" > /etc/apt/sources.list.d/docker.list
sudo aptitude update
sudo aptitude install docker-engine

Получение сертификата

Для автоматизации получения сертификата была разработана утилита letsencrypt. Код открыт, написан на Python, можно даже поизучать в случае сомнений в безопасности.

Для получение сертификата необходимо подтвердить права на владения доменом. В качестве подтверждения предлагается разместить специальный (генерируемый утилитой letsencrypt) файл в root - для этого есть несколько способов:

  1. Запустить letsencrypt в режиме webroot и донастроить nginx.
  2. Погасить на время Nginx и запустить letsencrypt в режиме standalone.

Я выбрал второй способ как более простой.

service nginx stop
docker run -it --rm -p 443:443 -p 80:80 --name letsencrypt -v "/etc/letsencrypt:/etc/letsencrypt" -v "/var/lib/letsencrypt:/var/lib/letsencrypt" quay.io/letsencrypt/letsencrypt:latest certonly -d <domen> -d <www.domen> --email <email> --agree-tos --renew-by-default
service nginx start

Где <domen> - доменное имя сайта, для которого получают сертификат (а <www.domen> - тот же домен с www), <email> - контактный email для восстановления. Опция --agree-tos необходима для автоматического согласия с условиями использования, а --renew-by-default позволяет получить сертификат даже в том случае, если период действия старых еще не истек. Стоит обратить внимание, что для корректной работы следует заказать сертификат как для версии сайта с www и без (www.domain.com и domain.com).

После выполнения по пути /etc/letsencrypt/live/<www.domain>/ будут располагаться свежеполученные сертификаты. В моем случае это путь /etc/letsencrypt/live/www.thenno.me/.

Настройка Nginx

Правильно настроенный Nginx должен проксировать все обращения по http на https, и с www.domain.com на domain.com (либо наоборот). Т.е большинстве случаев с http://domain.com, http://www.domain.com и https://www.domain.com на https://domain.com. В противном случае можно ожидать странного поведения от поисковых систем (вплоть до того, что все эти ресурсы будут считаться разными сайтами). За основу можно взять следующий конфиг (я не настоящий Nginx-джедай).

Общие настройки :

# /etc/nginx/ssl/domain.com
ssl_certificate /etc/letsencrypt/live/www.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

Настройки обработки запросов:

# /etc/nginx/sites-available/domain.com

# проксирование с www по 443 порту на non-www версию
# стоит обратить внимание, что эта версия тоже подписана сертификатом, иначе ничего работать не будет
server {
    listen 443 ssl;
    server_name www.domain.com;

    include /etc/nginx/ssl/domain.com;

    return 301 https://domain.com$request_uri;
}

# проксирование с http на https
server {
    listen 80;
    server_name domain.com www.domain.com;
    return 301 https://domain.com$request_uri;
}

server {
    listen 443 ssl;
    server_name domain.com;

    include /etc/nginx/ssl/domain.com;

    location {
        <...>
    }
}

И сделать

service nginx restart

Если все сделано правильно - при общении с сайтом будет использоваться защищенный https.

Автопродление

Я решил пойти самым простым способом - обновлением по cron раз в месяц (/etc/cron.monthly/letsencrypt):

#!/bin/sh
# letsencrypt cron monthly

 set -e

service nginx stop

docker run -it --rm -p 443:443 -p 80:80 --name letsencrypt -v "/etc/letsencrypt:/etc/letsencrypt" -v "/var/lib/letsencrypt:/var/lib/letsencrypt" quay.io/letsencrypt/letsencrypt:latest certonly -d <non-www domain> -d <www domain> --email <email> --agree-tos --renew-by-default

service nginx start

exit 0

Т.е остановить Nginx, запросить сертификат для www и non-www версий домена и стартовать Nginx опять.


Comments

comments powered by Disqus