Статьи

Как использовать SSL / TLS с Node.js

Пора! Больше никаких проволочек и плохих оправданий: Let’s Encrypt прекрасно работает, а создать сайт, защищенный SSL, проще, чем когда-либо.

В этой статье я рассмотрю практический пример того, как добавить сгенерированный Let’s Encrypt сертификат на ваш сервер Express.js.

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

Давайте начнем с краткого обзора текущего состояния HTTPS.

HTTPS везде

Спецификация HTTP / 2 была опубликована как RFC 7540 в мае 2015 года, что означает, что на данный момент она является частью стандарта. Это была главная веха. Теперь мы можем обновить наши серверы, чтобы использовать HTTP / 2. Одним из наиболее важных аспектов является обратная совместимость с HTTP 1.1 и механизм согласования для выбора другого протокола. Хотя стандарт не устанавливает обязательное шифрование, в настоящее время ни один браузер не поддерживает HTTP / 2 в незашифрованном виде Это дает HTTPS еще один импульс. Наконец-то мы получим HTTPS везде!

Как на самом деле выглядит наш стек? С точки зрения веб-сайта, работающего в браузере (уровень приложения), у нас есть примерно следующие уровни для достижения уровня IP:

  1. Клиентский браузер
  2. HTTP
  3. SSL / TLS
  4. TCP
  5. IP

HTTPS — это не более чем протокол HTTP поверх SSL / TLS. Следовательно, все правила HTTP все еще должны применяться. Что на самом деле дает нам этот дополнительный слой? Есть несколько преимуществ: мы получаем аутентификацию, имея ключи и сертификаты; гарантируется определенная конфиденциальность и конфиденциальность, поскольку соединение шифруется асимметричным образом; и целостность данных также сохраняется: эти передаваемые данные не могут быть изменены во время передачи.

Один из самых распространенных мифов заключается в том, что использование SSL / TLS требует слишком много ресурсов и замедляет работу сервера. Это, конечно, больше не правда. Нам также не нужно специализированное оборудование с криптографическими модулями. Даже для Google уровень SSL / TLS составляет менее 1% загрузки процессора. Кроме того, нагрузка на сеть HTTPS по сравнению с HTTP ниже 2%. В общем, не имеет смысла отказываться от HTTPS за небольшие накладные расходы.

TLS быстро еще?

Самая последняя версия — TLS 1.3. TLS является преемником SSL, который доступен в его последней версии SSL 3.0. Изменения с SSL на TLS исключают возможность взаимодействия. Основная процедура, однако, остается неизменной. У нас есть три разных зашифрованных канала. Первый — это инфраструктура открытых ключей для цепочек сертификатов. Второй обеспечивает криптографию с открытым ключом для обмена ключами. Наконец, третий симметричный. Здесь у нас есть криптография для передачи данных.

TLS 1.3 использует хеширование для некоторых важных операций. Теоретически, можно использовать любой алгоритм хеширования, но настоятельно рекомендуется использовать SHA2 или более сильный алгоритм. SHA1 долгое время был стандартом, но в последнее время устарел.

HTTPS также получает больше внимания для клиентов. Проблемы конфиденциальности и безопасности были всегда, но с ростом количества доступных в Интернете данных и услуг, люди становятся все более и более обеспокоенными. Полезный плагин для браузера — «HTTPS Everywhere», который шифрует нашу связь с большинством веб-сайтов.

HTTPS-везде

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

Основное общение

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

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

HTTPS-последовательность

Вся последовательность запускается независимо от HTTP. Если мы решим использовать HTTPS, будет изменена только обработка сокетов. Клиент по-прежнему отправляет HTTP-запросы, но сокет будет выполнять ранее описанное рукопожатие и шифровать содержимое (заголовок и тело).

Итак, что нам нужно для работы SSL / TLS с сервером Express.js?

HTTPS

По умолчанию Node.js обслуживает контент по HTTP. Но есть также модуль HTTPS, который мы должны использовать для связи по безопасному каналу с клиентом. Это встроенный модуль, и его использование очень похоже на использование модуля HTTP:

const https = require("https"), fs = require("fs"); const options = { key: fs.readFileSync("/srv/www/keys/my-site-key.pem"), cert: fs.readFileSync("/srv/www/keys/chain.pem") }; const app = express(); app.use((req, res) => { res.writeHead(200); res.end("hello world\n"); }); app.listen(8000); https.createServer(options, app).listen(8080); 

/srv/www/keys/my-site-key.pem /srv/www/keys/chain.pem файлы /srv/www/keys/my-site-key.pem и /srv/www/keys/chain.pem . Это те SSL-сертификаты, которые нам нужно сгенерировать, что мы сделаем чуть позже. Это та часть, которая изменилась с Let’s Encrypt. Раньше нам приходилось генерировать пару секретных / открытых ключей, отправлять их доверенным органам, платить им и, возможно, немного подождать, чтобы получить сертификат SSL. В настоящее время Let’s Encrypt генерирует и проверяет ваши сертификаты бесплатно и мгновенно!

Генерация сертификатов

Certbot

Сертификат, который подписан доверенным центром сертификации (CA), требуется спецификацией TLS. CA гарантирует, что владелец сертификата действительно тот, кем он себя называет. Поэтому, в основном, когда вы видите зеленый значок замка (или любой другой зеленоватый знак слева от URL-адреса в вашем браузере), это означает, что сервер, с которым вы общаетесь, действительно является тем, кем он себя считает. Если вы находитесь на facebook.com и видите зеленый замок, почти наверняка вы общаетесь с Facebook, и никто больше не может видеть ваше общение — или, точнее, никто не может его прочитать.

Стоит отметить, что этот сертификат не обязательно должен быть проверен таким органом, как Let’s Encrypt. Есть и другие платные услуги. Технически вы можете подписать его самостоятельно, но тогда пользователи, посещающие ваш сайт, не получат одобрения со стороны ЦС при посещении, и все современные браузеры покажут пользователю большой флаг предупреждения и попросят перенаправить их «в безопасность».

В следующем примере мы будем использовать Certbot , который используется для генерации и управления сертификатами с Let’s Encrypt.

На сайте Certbot вы можете найти инструкции по установке Certbot в вашей ОС. Здесь мы будем следовать инструкциям macOS. Чтобы установить Certbot , запустите

 brew install certbot 

Webroot

Webroot — это плагин Certbot, который, в дополнение к функции по умолчанию Certbot, автоматически генерирует пару открытых и закрытых ключей и генерирует для них сертификат SSL, также копирует сертификаты в папку webroot, а также проверяет сервер, помещая некоторые коды проверки в скрытый временный каталог с именем .well-known . Чтобы пропустить выполнение некоторых из этих шагов вручную, мы будем использовать этот плагин. Плагин устанавливается по умолчанию вместе с Certbot . Чтобы сгенерировать и проверить наши сертификаты, мы запустим следующее:

 certbot certonly --webroot -w /var/www/example/ -d www.example.com -d example.com 

Возможно, вам придется выполнить эту команду как sudo, так как она попытается записать в /var/log/letsencrypt .

Вам также будет предложено указать ваш адрес электронной почты. Хорошей идеей будет ввести реальный адрес, который вы часто используете, так как вы получите уведомление, когда истекает срок действия вашего сертификата. Обмен на бесплатное свидетельство Let’s Encrypt заключается в том, что срок его действия истекает каждые три месяца. К счастью, обновление так же просто, как и запуск одной простой команды, которую мы можем назначить хрону, и тогда не нужно беспокоиться об истечении срока действия. Кроме того, рекомендуется обновлять сертификаты SSL, так как у злоумышленников меньше времени для взлома шифрования. Иногда разработчики даже настраивают этот cron для ежедневного запуска, что вполне нормально и даже рекомендуется.

Помните, что вы должны выполнить эту команду на сервере, на котором разрешен домен, указанный под флагом -d (для домена), то есть на вашем производственном сервере. Даже если у вас есть разрешение DNS в вашем локальном файле hosts, это не сработает, так как домен будет проверен извне. Так что, если вы делаете это локально, это, скорее всего, не будет работать вообще, если вы не открыли порт с вашего локального компьютера на внешний и не запустили его за доменным именем, которое разрешается для вашего компьютера, что крайне маловероятно сценарий.

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

 // ... const options = { key: fs.readFileSync("/var/www/example/sslcert/privkey.pem"), cert: fs.readFileSync("/var/www/example/sslcert/fullchain.pem") // these paths might differ for you, make sure to copy from the certbot output }; // ... 

Tighetning It Up

HSTS

У вас когда-нибудь был веб-сайт, на котором вы переключились с HTTP на HTTPS, и были некоторые остаточные перенаправления, все еще перенаправляющие на HTTP? HSTS — это механизм политики веб-безопасности, предназначенный для предотвращения атак с использованием более ранних версий протоколов и захвата файлов cookie.

HSTS эффективно вынуждает клиента (браузер, обращающийся к вашему серверу) направлять весь трафик через HTTPS — идеология «безопасная или нет»!

Express JS не позволяет нам добавлять этот заголовок по умолчанию, поэтому мы будем использовать Helmet , модуль узлов, который позволяет нам это делать. Установите шлем , запустив

 npm install --save helmet 

Тогда нам просто нужно добавить его в качестве промежуточного программного обеспечения на наш сервер Express:

 const https = require("https"), fs = require("fs"), helmet = require("helmet"); const options = { key: fs.readFileSync("/srv/www/keys/my-site-key.pem"), cert: fs.readFileSync("/srv/www/keys/chain.pem") }; const app = express(); app.use(helmet()); // Add Helmet as a middleware app.use((req, res) => { res.writeHead(200); res.end("hello world\n"); }); app.listen(8000); https.createServer(options, app).listen(8080); 

Параметры Диффи – Хеллмана

Чтобы пропустить сложную математику, давайте перейдем к погоне. Проще говоря, для шифрования используются два разных ключа: сертификат, который мы получаем от центра сертификации, и один, который генерируется сервером для обмена ключами. Ключ по умолчанию для обмена ключами (также называемый обмен ключами Диффи-Хеллмана или DH) использует ключ «меньшего размера», чем ключ для сертификата. Чтобы исправить это, мы создадим надежный ключ DH и отправим его на наш защищенный сервер для использования.

Чтобы сгенерировать более длинный (2048 бит) ключ, вам понадобится openssl , который вы, вероятно, установили по умолчанию. Если вы не уверены, запустите openssl -v . Если команда не найдена, установите openssl , запустив brew install openssl :

 openssl dhparam -out /var/www/example/sslcert/dh-strong.pem 2048 

Затем скопируйте путь к файлу в нашу конфигурацию:

 // ... const options = { key: fs.readFileSync("/var/www/example/sslcert/privkey.pem"), cert: fs.readFileSync("/var/www/example/sslcert/fullchain.pem"), // these paths might differ for you, make sure to copy from the certbot output dhparam: fs.readFileSync("/var/www/example/sslcert/dh-strong.pem") }; // ... 

Вывод

В 2018 году и за его пределами нет никаких оснований для увольнения HTTPS. Будущее направление ясно видно — везде HTTPS! В Node.js у нас есть много вариантов использования SSL / TLS. Мы можем публиковать наши веб-сайты в формате HTTPS, мы можем создавать запросы к зашифрованным веб-сайтам и разрешать иным образом ненадежные сертификаты.

Что вы думаете о HTTPS везде? Существуют ли пакеты Node.js для всего связанного с SSL / TLS, который вы бы порекомендовали?