Ошибка: невозможно проверить первый сертификат в nodejs


144

Я пытаюсь загрузить файл с сервера jira, используя URL-адрес, но получаю сообщение об ошибке. как включить сертификат в код для проверки ошибки:

Error: unable to verify the first certificate in nodejs

at Error (native)
    at TLSSocket.<anonymous> (_tls_wrap.js:929:36)

  at TLSSocket.emit (events.js:104:17)

at TLSSocket._finishInit (_tls_wrap.js:460:8)

Мой код Nodejs:

var https = require("https");
var fs = require('fs');
var options = {
    host: 'jira.example.com',
    path: '/secure/attachment/206906/update.xlsx'
};

https.get(options, function (http_res) {

    var data = "";


    http_res.on("data", function (chunk) {

        data += chunk;
    });


    http_res.on("end", function () {

        var file = fs.createWriteStream("file.xlsx");
        data.pipe(file);

    });
});

Вы смогли это решить?
Шарад Джайн

2
Я использовал другую процедуру, такую ​​как отключение проверки сертификата, и готово
Лабео

можешь уточнить немного подробнее? Это будет действительно полезно для меня
Шарад Джайн

см ниже ответ для проверки сертификата мы должны иметь rejectUnauthorized
Лабеон

Ответы:


122

Попробуйте добавить соответствующий корневой сертификат

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

Это может быть так же просто, как добавить

require('https').globalAgent.options.ca = require('ssl-root-cas/latest').create();

в ваше приложение.

НПЙ пакет SSL корневых центров сертификации (как здесь используется) очень полезный пакет относительно этой проблемы.


9
Этот ответ следует использовать в большинстве случаев, поскольку он фактически решает проблему, а не отключает все преимущества SSL.
mikemaccana

12
Как указано в модуле ssl-root-cas README, одной из наиболее частых причин этой проблемы является то, что в ваш сертификат не встроены сертификаты промежуточного ЦС. Попытайтесь исправить свой сертификат, прежде чем пытаться что-либо еще;)
Laurent VB

Вам может даже не потребоваться пакет SSL-root-cas. Просто установите globalAgents.option.cert на сертификат полной цепи. Вот что решило мою проблему.
smartexpert 05

2
mkcert не создает сертификат «полной цепи». Вы должны объединить свой сертификат с корневым сертификатом, доступным $(mkcert -CAROOT)/rootCA.pemв новом файле сертификата, и сделать что-то вроде https.globalAgent.options.ca = fs.readFileSync('fullchain.pem')См. Github.com/FiloSottile/mkcert/issues/76
Frosty Z

Из соображений безопасности в ssl-root-casмодуле npm есть запрос к жестко запрограммированному mozilla.org git.coolaj86.com/coolaj86/ssl-root-cas.js/src/branch/master/… . Вероятно, это безопасно, потому что Mozilla, но похоже на вектор атаки.
Авиндра Гулчаран,

63

Еще один грязный прием, который сделает все ваши запросы небезопасными:

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0

8
Кажется, это не отличается от ответа Лабео выше , что не менее опасно.
ocramot

4
Он другой, он не требует каких-либо изменений кодирования, поскольку переменная env может быть установлена ​​вне исходного кода.
jzacharuk

1
Этот ответ опасен. Вы отключаете любую безопасность, которую обеспечивает TLS.
Flimm

2
Это сработало для меня, очень полезно. В моем случае я просто разговариваю с localhost , поэтому проблема не в безопасности.
Mike S

Действительно хорошо, просто протестировать localhost. Просто убедитесь, что вы удалили его после тестов.
Нико

44

для невозможности проверить первый сертификат в nodejs необходимо отклонить неавторизованный

 request({method: "GET", 
        "rejectUnauthorized": false, 
        "url": url,
        "headers" : {"Content-Type": "application/json",
        function(err,data,body) {
    }).pipe(
       fs.createWriteStream('file.html'));

130
Этот ответ опасен. Другой безопаснее.
mikemaccana

3
Делая это, вы удаляете защиту, обеспечиваемую SSL, поэтому его следует использовать только для разработки.
Sylvain

11
Отсутствие проверки сертификатов означает, что вы не можете быть уверены в идентичности другой стороны и, следовательно, можете подвергнуться подделке хоста. Однако даже если вы не проверяете сертификаты, вы все равно получаете зашифрованное сообщение, которое не может быть (легко) отслежено. Таким образом, добавление этой строки не «снимает безопасность» SSL или, как сказал другой комментатор, «отключает [] все преимущества SSL».
Боб Поллак,

4
Отключение проверки SSL НЕ является решением какой-либо проблемы. :-)
Сиддху

9
Это работает, если вы используете библиотеку запросов узлов. Какая я. И спасибо, это решает мою непосредственную потребность в развитии.
Алан

29

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

Рекомендую проверить сайт в инструменте SSLlabs: https://www.ssllabs.com/ssltest/

Ищите эту ошибку:

Цепочка сертификатов этого сервера неполная.

И это:

Проблемы с цепочкой ......... Не завершено


У меня возникает эта проблема (проблемы с цепочкой ......... Неполный) для моего сертификата, который авторизован DigiCert Inc., как это исправить?
imarchuang

@imarchuang Короче говоря, ваш сервер должен обслуживать не только сертификат для вашего домена, но и промежуточные сертификаты. Я не могу вместить больше деталей в этот комментарий, но, надеюсь, этого достаточно, чтобы указать вам правильное направление.
Flimm

спасибо большое, мы выяснили,
прочесав

Спасибо вам! Я обнаружил, что мой сертификат был неполным, хотя он отлично работал в chrome и firefox, но не работал в электронном приложении, и я исправил его на nginx рядомcat domainname.crt domainname.ca-bundle > domainname-ssl-bundle.crt
Иван Борщов

26

unable to verify the first certificate

Цепочка сертификатов неполная.

Это означает, что веб-сервер, к которому вы подключаетесь, неправильно настроен и не включил промежуточный сертификат в цепочку сертификатов, которую он вам отправил.

Цепочка сертификатов

Скорее всего, это выглядит так:

  1. Сертификат сервера - хранит сертификат, подписанный промежуточным звеном.
  2. Промежуточный сертификат - хранит сертификат, подписанный root.
  3. Корневой сертификат - хранит самозаверяющий сертификат.

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

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

Воссоздайте проблему

Перейдите на https://incomplete-chain.badssl.com в браузере.

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

Теперь подключитесь к https://incomplete-chain.badssl.com, используя Node:

// index.js
const axios = require('axios');

axios.get('https://incomplete-chain.badssl.com')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

Журналы: « Ошибка: не удалось проверить первый сертификат ».

Решение

Вам необходимо самостоятельно заполнить цепочку сертификатов.

Для этого:

1: Вам нужно получить недостающий промежуточный сертификат в .pemформате, затем

2a: расширить встроенное хранилище сертификатов Node, используя NODE_EXTRA_CA_CERTS,

2b: или передайте собственный комплект сертификатов (промежуточные и корневой) с помощью caoption.

1. Как получить промежуточный сертификат?

Использование openssl(поставляется с Git для Windows ).

Сохраните данные сертификата удаленного сервера:

openssl s_client -connect incomplete-chain.badssl.com:443 -servername incomplete-chain.badssl.com | tee logcertfile

Ищем эмитента (промежуточный сертификат является эмитентом / подписчиком сертификата сервера):

openssl x509 -in logcertfile -noout -text | grep -i "issuer"

Он должен предоставить вам URI сертификата подписи. Загрузить:

curl --output intermediate.crt http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt

Наконец, преобразуйте его в .pem:

openssl x509 -inform DER -in intermediate.crt -out intermediate.pem -text

2а. NODE_EXTRA_CERTS

Я использую cross-env для установки переменных среды в package.jsonфайле:

"start": "cross-env NODE_EXTRA_CA_CERTS=\"C:\\Users\\USERNAME\\Desktop\\ssl-connect\\intermediate.pem\" node index.js"

2b. caвариант

Эта опция будет перезаписывать встроенные корневые центры сертификации узла.

Вот почему нам нужно создать собственный корневой ЦС. Используйте ssl-root-cas .

Затем создайте настраиваемый httpsагент, настроенный с помощью нашего пакета сертификатов (корневой и промежуточный). Передайте этого агента axiosпри отправке запроса.

// index.js
const axios = require('axios');
const path = require('path');
const https = require('https');
const rootCas = require('ssl-root-cas').create();

rootCas.addFile(path.resolve(__dirname, 'intermediate.pem'));
const httpsAgent = new https.Agent({ca: rootCas});

axios.get('https://incomplete-chain.badssl.com', { httpsAgent })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

Вместо того, чтобы создавать настраиваемый httpsагент и передавать его axios, вы можете разместить сертификаты на httpsглобальном агенте:

// Applies to ALL requests (whether using https directly or the request module)
https.globalAgent.options.ca = rootCas;

Ресурсы:

  1. https://levelup.gitconnected.com/how-to-resolve-certificate-errors-in-nodejs-app-involving-ssl-calls-781ce48daded
  2. https://www.npmjs.com/package/ssl-root-cas
  3. https://github.com/nodejs/node/issues/16336
  4. https://www.namecheap.com/support/knowledgebase/article.aspx/9605/69/how-to-check-ca-chain-installation
  5. /superuser/97201/how-to-save-a-remote-server-ssl-certificate-locally-as-a-file/
  6. Как конвертировать .crt в .pem

Очень подробное объяснение.
Семь

1
Совершенно потрясающе! У меня не вышло, но какая деталь!
Том Чадаравичус,

6

Это фактически решило это для меня, из https://www.npmjs.com/package/ssl-root-cas

// INCORRECT (but might still work)
var server = https.createServer({
  key: fs.readFileSync('privkey.pem', 'ascii'),
  cert: fs.readFileSync('cert.pem', 'ascii') // a PEM containing ONLY the SERVER certificate
});

// CORRECT (should always work)
var server = https.createServer({
  key: fs.readFileSync('privkey.pem', 'ascii'),
  cert: fs.readFileSync('fullchain.pem', 'ascii') // a PEM containing the SERVER and ALL INTERMEDIATES
});

1
Это лучшее решение, imho, поскольку оно не требует дополнительных библиотек и простое
Мартин Шнайдер

4

Вы можете сделать это, изменив параметры запроса, как показано ниже. Если вы используете самозаверяющий сертификат или отсутствующего посредника, установка для strictSSL значения false не приведет к принудительному пакету запроса для проверки сертификата.

var options = {
   host: 'jira.example.com',
   path: '/secure/attachment/206906/update.xlsx',
   strictSSL: false
}

Это решило мою проблему, я использую модуль «запрос» вместо «http». Спасибо!
Бруно Нуньес

2

Сертификат GoDaddy SSL CC

Я испытал это, пытаясь подключиться к нашему внутреннему серверу API с сертификатом GoDaddy, и вот код, который я использовал для решения проблемы.

var rootCas = require('ssl-root-cas/latest').create();

rootCas
  .addFile(path.join(__dirname, '../config/ssl/gd_bundle-g2-g1.crt'))
  ;

// will work with all https requests will all libraries (i.e. request.js)
require('https').globalAgent.options.ca = rootCas;

PS:

Используйте прилагаемый сертификат и не забудьте установить библиотеку npm install ssl-root-cas


1
это сработало для меня, за исключением того, что при импорте мне пришлось использовать «ssl-root-cas» вместо «ssl-root-cas / latest».
Кришнан

2

Это сработало для меня => добавление агента и для параметра rejectUnauthorized установлено значение false

const https = require('https'); //Add This
const bindingGridData = async () => {
  const url = `your URL-Here`;
  const request = new Request(url, {
    method: 'GET',
    headers: new Headers({
      Authorization: `Your Token If Any`,
      'Content-Type': 'application/json',
    }),
    //Add The Below
    agent: new https.Agent({
      rejectUnauthorized: false,
    }),
  });
  return await fetch(request)
    .then((response: any) => {
      return response.json();
    })
    .then((response: any) => {
      console.log('response is', response);
      return response;
    })
    .catch((err: any) => {
      console.log('This is Error', err);
      return;
    });
};


1

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

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

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


-3

Я использовал модуль nodemailer npm. Приведенный ниже код решил проблему

     tls: {
     // do not fail on invalid certs
     rejectUnauthorized: false
     }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.