Если вам уже доводилось писать приложения на Node/Express, то вы не понаслышке знаете, что такие приложения обычно устанавливаются с HTTPS
и сертификатом сервера. Однако в рабочей среде Node.js HTTPS
, как правило, не требуется, поскольку Node-приложения прикрыты обратным прокси-сервером (например, Nginx
), который и обслуживает сертификаты.
Скорее всего, ваше Node-приложение будет работать как клиент, и ему придется вызывать серверные службы, защищенные HTTPS
. По умолчанию Node.js создается с набором часто используемых корневых сертификатов центров сертификации (СА). Но и здесь мы не застрахованы от ошибок в случаях, если Node-приложение осуществляет HTTPS
API-вызов серверных служб с самоподписанными сертификатами (например, частных корпоративных СА). Примеры ошибок:
UNABLE_TO_GET_ISSUER_CERT_LOCALLY
UNABLE_TO_VERIFY_LEAF_SIGNATURE
DEPTH_ZERO_SELF_SIGNED_CERT
Для устранения этих ошибок потребуется найти их источник.
SSL-рукопожатие
Такие ошибки возникают в процессе SSL
-рукопожатия. Клиент пытается установить соединение с сервером через TLS
-рукопожатие. TLS
-рукопожатие — это обмен сообщениями между клиентом и сервером, в ходе которого они договариваются о версии TLS
и комбинации шифров, подтверждают подлинность сервера, а также генерируют ключи сессии.
В шаге 2 сервер отправляет сообщение со своим SSL
-сертификатом, а клиент проверяет его через СА, выпустившего данный сертификат. Так подтверждается подлинность сервера, и клиент взаимодействует с истинным владельцем домена.
Эти ошибки возникают в случаях, когда клиент не может проверить самоподписанный сертификат сервера из шага 2.
rejectUnauthorized
Простейший способ по устранению подобных ошибок заключается в использовании rejectUnauthorized
.
https.request({
....,
rejectUnauthorized: false,
},
...)
Вы также можете задать ее в качестве переменной среды:
NODE_TLS_REJECT_UNAUTHORIZED=0
К сожалению, данный метод не безопасен, поскольку отключает проверку сертификата сервера, из-за чего Node-приложение становится уязвимым для так называемой “атаки посредника”. Получается, что данный способ допустим только в среде разработки, а не в рабочей среде.
Свойство ca
Более безопасным способом будет указать, какой именно CA-сертификат ожидается от сервера. Иначе говоря, название сертификата должно совпадать с сертификатом сервера.
request({
ca: [fs.readFileSync([certificate path])],
rejectUnauthorized: true,
}
Как вы могли заметить, ca
— это массив, в котором при желании можно прописать несколько файлов сертификатов. Минус данного решения в том, что сертификат прописывается в самом в коде. Это весьма чревато в случае, когда нам нужно управлять несколькими версиями сертификатов в разных средах.
NODE_EXTRA_CA_CERTS
В Node версии 7.3.0 и выше появилась переменная среды NODE_EXTRA_CA_CERTS
, которая передается в файл СА-сертификата. Это позволяет дополнять «корневые» CA другими сертификатами. Сам файл сертификата должен состоять как минимум из одного доверенного сертификата в PEM
-формате.
Обратите внимание, что дополнительные сертификаты не имеют никакой силы, если в HTTPS
-клиенте или сервере явно прописано свойство ca
.
Как все исправить?
Чтобы избавиться от ошибок сертификатов, следует пользоваться свойством ca
или NODE_EXTRA_CA_CERTS
. Но появление тех же сообщений об ошибках все еще возможно. Как правило, это вызвано использованием неправильного сертификата. Для каждого из представленных вариантов вы должны получать полную цепочку сертификатов либо иметь как минимум один корневой сертификат CA.
Получить полную цепочку сертификатов можно через OpenSSL:
openssl s_client -connect ${REMHOST}:${REMPORT}
Пример цепочки сертификатов:
Читайте также:
- Потоки и буферы в Node.js
- 7 бесплатных Node пакетов с открытым исходным кодом
- Как создать HTML-таблицу и PDF с Node и Google Puppeteer
Перевод статьи Sunny Sun: How to Resolve Certificate Errors in a Node.js App with SSL Calls