Невозможно проверить листовую подпись

146

Я использую node.js request.js для доступа к api. Я получаю эту ошибку

[Ошибка: UNABLE_TO_VERIFY_LEAF_SIGNATURE]

Все мои учетные данные точны и действительны, и сервер в порядке. Я сделал то же самое с почтальоном

request({
    "url": domain+"/api/orders/originator/"+id,
    "method": "GET",
    "headers":{
        "X-API-VERSION": 1,
        "X-API-KEY": key
    },
}, function(err, response, body){
    console.log(err);
    console.log(response);
    console.log(body);
});

Этот код просто выполняется в исполняемом скрипте ex. node ./run_file.js, Вот почему? Нужно ли запускать на сервере?

ThomasReggi
источник
Это маловероятно, но может ли быть так, что API не распознает пользовательский агент, передаваемый вашей программой узла?
Hector Correa
1
Хм ... также посмотрите это: blog.gaeremynck.com/fixing-unable_to_verify_leaf_signature
Гектор Корреа
@HectorCorrea Я смог отлично прочитать api в почтальоне. Почему узел не может этого сделать? Я попытался изменить пользовательский агент, не повезло.
ThomasReggi

Ответы:

159

Примечание : следующее опасно и позволит перехватить и изменить содержимое API между клиентом и сервером.

Это тоже сработало

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';

ThomasReggi
источник
22
Я изменил это и спасибо за ответ, но это серьезно вредно для вашей безопасности. Вы должны добавить недостающий CA на ответ @ CoolAJ86 ниже.
mikemaccana 02
4
Я использую плагин NodeJS, nodemailerи nodemailer-smtp-transportработала та же общая команда. Вам нужно добавить это к своему createTransportобъекту:tls:{rejectUnauthorized: false}
LukeP
3
Думаю, @LukeP одинаково небезопасен с nodemailer. Там есть ключ от имени: если что - то Un разрешено, вы вообще хотите отклонить его, по определению. Что вам нужно, так это найти способ правильно авторизовать его (правильно настроив сертификаты CA, как уже говорили другие ответы).
Бруно
@Bruno Я согласен, вы должны правильно настроить сертификаты. Я просто хотел настроить быстрый тест для демонстрации, поэтому опубликованный мной код является быстрым исправлением. Я должен был сделать это предисловием в своем комментарии.
LukeP 03
1
@mikemaccana Нет проблем с безопасностью, если запрос находится на том же сервере, и вы единственный владелец.
Binar Web
89

Проблема не в приложении, а в сертификате, подписанном промежуточным ЦС. Если вы согласны с этим фактом и все же хотите продолжить, добавьте в параметры запроса следующее:

rejectUnauthorized: false

Полный запрос:

request({
    "rejectUnauthorized": false,
    "url": domain+"/api/orders/originator/"+id,
    "method": "GET",
    "headers":{
        "X-API-VERSION": 1,
        "X-API-KEY": key
    },
}, function(err, response, body){
    console.log(err);
    console.log(response);
    console.log(body);
});
Андрей Карпушонак
источник
У меня эта проблема сейчас на работе. Я отправил ИТ-билет, в котором говорилось, что SSL может быть неправильно настроен - они сказали мне, что я сошел с ума. Могу ли я предоставить им дополнительную информацию для решения этой проблемы?
blakev
На самом деле это неверно: как упоминают CoolAJ86 и hectorcorrea, сертификат действителен, но подписан промежуточным центром сертификации.
mikemaccana 02
81

Безопасное решение

Вместо отключения безопасности вы можете добавить в цепочку необходимые сертификаты. Сначала установите пакет ssl-root-cas из npm:

npm install ssl-root-cas

Этот пакет содержит множество промежуточных сертификатов, которым доверяют браузеры, но не node.

var sslRootCAs = require('ssl-root-cas/latest')
sslRootCAs.inject()

Добавлю недостающие сертификаты. См. Здесь для получения дополнительной информации:

https://git.coolaj86.com/coolaj86/ssl-root-cas.js

Также см. Следующий ответ ниже

coolaj86
источник
2
Клиент Http не использует хранилище сертификатов доверенных корневых центров сертификации Windows?
Ричард Коллетт
1
node использует сертификаты Mozilla, включенные в двоичный файл, и переопределяет их всякий раз, когда вы предоставляете свой собственный caмассив. Я не знаю, будет ли его http-модуль также обращаться к цепочке ОС. Однако curl в OS X, похоже, использует только цепочку ОС и не позволяет вручную указывать сертификаты.
coolaj86
Это нужно запускать для каждого процесса, или я могу запустить его один раз и обновить свои сертификаты глобально?
Джошуа Снайдер
Сертификаты потенциально хранятся в двух местах: (1) встроены в двоичный файл node.js (2) в хранилище ключей операционной системы. Если ваши сертификаты устарели, вам нужно будет включить это в свой рабочий код. Он не меняет ни двоичный файл узла, ни вашу операционную систему - только папку проекта.
coolaj86 05
1
@Sunkas Это именно то, что написано в сообщениях об ошибках. Я не знаю, как это объяснить проще. Это файл только для чтения и его нельзя редактировать.
coolaj86
45

Решение CoolAJ86 правильное, и оно не ставит под угрозу вашу безопасность, например отключение всех проверок с помощью rejectUnauthorizedилиNODE_TLS_REJECT_UNAUTHORIZED . Тем не менее, вам может потребоваться явное введение дополнительного сертификата CA.

Сначала я попробовал корневые центры сертификации, включенные в модуль ssl-root-cas :

require('ssl-root-cas/latest')
  .inject();

Я все равно получил UNABLE_TO_VERIFY_LEAF_SIGNATUREошибку. Затем я узнал, кто выпустил сертификат для веб-сайта, к которому я подключаюсь с помощью COMODO SSL Analyzer , скачал сертификат этого органа и попытался добавить только его:

require('ssl-root-cas/latest')
  .addFile(__dirname + '/comodohigh-assurancesecureserverca.crt');

Я закончил с другой ошибкой: CERT_UNTRUSTED. Наконец, я ввел дополнительные корневые центры сертификации и включил «мой» (по-видимому, промежуточный), который работал:

require('ssl-root-cas/latest')
  .inject()
  .addFile(__dirname + '/comodohigh-assurancesecureserverca.crt');
Фердинанд Прантль
источник
1
Я подключался к веб-сайту с сертификатом, выданным COMODO High-Assurance Secure Server CA. Я скачал сертификат с их страницы загрузок .
Фердинанд Прантл
2
Спасибо! Для моей проблемы мне нужно было добавить всю цепочку сертификатов, чтобы обойти эту ошибку. Для других справок, этот пост показал мне, как легко экспортировать необходимые файлы pem через Firefox: superuser.com/a/97203
mfink
Что ж, спасибо за помощь. В моем случае это была плохая конфигурация сервера SSL, а не узла. Не все промежуточные сертификаты были установлены на сервере.
Скотт Юнгвирт
если вы получили сертификат как .cerзапуск, это, openssl x509 -inform DER -in YOUR_CERTIFICATE.cer -out YOUR_CERTIFICATE.crtчтобы преобразовать его .crtзаранее
0x1gene
9

Для приложения Create React (где также возникает эта ошибка, и этот вопрос является результатом №1 Google) вы, вероятно, используете HTTPS=true npm startи proxypackage.json ), который переходит к некоторому HTTPS API, который сам подписывается, когда находится в разработке.

Если это так, подумайте об изменении proxyследующим образом:

"proxy": {
  "/api": {
    "target": "https://localhost:5001",
    "secure": false
  }
}

secure решает, проверяет ли прокси-сервер WebPack цепочку сертификатов или нет, и его отключение гарантирует, что самозаверяющий сертификат API не будет проверен, чтобы вы получили свои данные.

Томаш Хюбельбауэр
источник
4

Это может быть очень заманчиво сделать rejectUnauthorized: falseилиprocess.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; , но не делайте этого! Он подвергает вас атаке человека в середине.

Другие ответы верны, поскольку проблема заключается в том, что ваш сертификат «подписан промежуточным центром сертификации». Для этого есть простое решение, которое не требует сторонней библиотеки, напримерssl-root-cas добавление каких-либо дополнительных центров сертификации в узел.

Большинство https-клиентов в опциях поддержки узлов, которые позволяют указать ЦС для каждого запроса, который будет разрешен UNABLE_TO_VERIFY_LEAF_SIGNATURE. Вот простой пример использования встроенного httpsмодуля узла .

import https from 'https';

const options = {
  host: '<your host>',
  defaultPort: 443,
  path: '<your path>',
  // assuming the bundle file is co-located with this file
  ca: readFileSync(__dirname + '/<your bundle file>.ca-bundle'),
  headers: {
    'content-type': 'application/json',
  }
};
https.get(options, res => {
  // do whatever you need to do
})

Однако если вы можете настроить параметры ssl на своем хостинг-сервере, лучшим решением будет добавить промежуточные сертификаты к вашему хостинг-провайдеру. Таким образом, инициатору запроса клиента не нужно указывать ЦС, поскольку он включен в сам сервер. Я лично использую namecheap + heroku. Уловкой для меня было создать один файл .crt с расширением cat yourcertificate.crt bundle.ca-bundle > server.crt. Затем я открыл этот файл и добавил новую строку после первого сертификата. Вы можете узнать больше на

https://www.namecheap.com/support/knowledgebase/article.aspx/10050/33/installing-an-ssl-certificate-on-heroku-ssl

Саймон
источник
Эта ошибка возникает в основном в локальной среде, а не в производственной среде, поэтому, если вы находитесь в локальной среде, это нормально: process.env ['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
vivex
@Vivex - это не нормально делать это в локальной среде, если все дело в том, чтобы проверить, как работают ваши сертификаты SSL и как они передаются ...
Двандерсон,
2

Просто поместите это здесь на случай, если это кому-то поможет, мой случай был другим и немного странным. Я получал это по запросу, к которому обращались через суперагента - проблема не имела ничего общего с сертификатами (которые были настроены правильно), а все из-за того, что я затем передавал результат суперагента через обратный вызов водопада асинхронного модуля. Чтобы исправить: вместо того, чтобы передавать весь результат, просто передайте result.bodyобратный вызов водопада.

k00k
источник
2

У меня были такие же проблемы. Я следил за решениями @ThomasReggi и @ CoolAJ86 и работал хорошо, но я не удовлетворен решением.

Поскольку проблема «UNABLE_TO_VERIFY_LEAF_SIGNATURE» возникает из-за уровня конфигурации сертификации.

Я принимаю решение @thirdender, но его частичное решение. Согласно официальному сайту nginx , они четко упомянули, что сертификат должен быть комбинацией сертификата сервера и связанных сертификатов.

введите описание изображения здесь

Шарати РБ
источник
2

Вы также можете попробовать, установив strictSSL к false, как это:

{  
   url: "https://...",
   method: "POST",
   headers: {
        "Content-Type": "application/json"},
   strictSSL: false
}
СУБХАДЖИТ ГАНГУЛИ
источник
Это работает, если вы отправляете из приложения Node JS, отлично !!
Элли Маконго
Спасибо!!! У меня это работает, вау, после того, как я провел столько времени ...
Нан
0

У меня возникла проблема с конфигурацией Apache после установки сертификата GoDaddy на поддомене. Первоначально я думал, что это может быть проблема с узлом, который не отправляет индикатор имени сервера (SNI), но это было не так. Анализ SSL-сертификата субдомена с https://www.ssllabs.com/ssltest/ вернул ошибку Цепочка вопросов: Неполный .

После добавления gd_bundle-g2-g1.crtфайла, предоставленного GoDaddy с помощью SSLCertificateChainFileдирективы Apache, Node смог подключиться через HTTPS, и ошибка исчезла.

триадер
источник
0

Вы должны включить промежуточный сертификат на свой сервер. Это решает [Ошибка: UNABLE_TO_VERIFY_LEAF_SIGNATURE]


источник
0

Другой подход к безопасному решению этой проблемы - использовать следующий модуль.

node_extra_ca_certs_mozilla_bundle

Этот модуль может работать без каких-либо изменений кода, создавая файл PEM, который включает все корневые и промежуточные сертификаты, которым доверяет Mozilla. Вы можете использовать следующую переменную среды (работает с Nodejs v7.3 +),

NODE_EXTRA_CA_CERTS

Чтобы создать файл PEM для использования с указанной выше переменной среды. Вы можете установить модуль, используя:

npm install --save node_extra_ca_certs_mozilla_bundle

а затем запустите сценарий узла с переменной среды.

NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_intermediate_root_bundle.pem node your_script.js

Другие способы использования сгенерированного файла PEM доступны по адресу:

https://github.com/arvind-agarwal/node_extra_ca_certs_mozilla_bundle

ПРИМЕЧАНИЕ: я являюсь автором вышеуказанного модуля.

Арва
источник
0

Если вы зашли в эту ветку, потому что используете модуль node postgres / pg, есть лучшее решение, чем установка NODE_TLS_REJECT_UNAUTHORIZEDилиrejectUnauthorized , что приведет к небезопасным соединениям.

Вместо этого настройте параметр «ssl» в соответствии с параметрами для tls.connect :

{
  ca: fs.readFileSync('/path/to/server-ca.pem').toString(),
  cert: fs.readFileSync('/path/to/client-cert.pem').toString(),
  key: fs.readFileSync('/path/to/client-key.pem').toString(),
  servername: 'my-server-name' // e.g. my-project-id/my-sql-instance-id for Google SQL
}

Я написал модуль для помощи при разборе этих параметров от переменных окружения , как PGSSLROOTCERT, PGSSLCERTи PGSSLKEY:

https://github.com/programmarchy/pg-ssl

Дональд
источник
-2

У меня работали следующие команды:

> npm config set strict-ssl false
> npm cache clean --force

Проблема в том, что вы пытаетесь установить модуль из репозитория с плохим или ненадежным сертификатом SSL [Secure Sockets Layer]. Как только вы очистите кеш, эта проблема будет решена. Возможно, позже вам потребуется изменить его значение на true.

Шагун Прути
источник