unable to verify the first certificate
Цепочка сертификатов неполная.
Это означает, что веб-сервер, к которому вы подключаетесь, неправильно настроен и не включил промежуточный сертификат в цепочку сертификатов, которую он вам отправил.
Цепочка сертификатов
Скорее всего, это выглядит так:
- Сертификат сервера - хранит сертификат, подписанный промежуточным звеном.
- Промежуточный сертификат - хранит сертификат, подписанный root.
- Корневой сертификат - хранит самозаверяющий сертификат.
На сервере должен быть установлен промежуточный сертификат вместе с сертификатом сервера.
Корневые сертификаты встроены в программные приложения, браузеры и операционные системы.
Приложение, обслуживающее сертификат, должно отправить полную цепочку, то есть сам сертификат сервера и все промежуточные звенья. Предполагается, что корневой сертификат известен клиенту.
Воссоздайте проблему
Перейдите на 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: или передайте собственный комплект сертификатов (промежуточные и корневой) с помощью ca
option.
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;
Ресурсы:
- https://levelup.gitconnected.com/how-to-resolve-certificate-errors-in-nodejs-app-involving-ssl-calls-781ce48daded
- https://www.npmjs.com/package/ssl-root-cas
- https://github.com/nodejs/node/issues/16336
- https://www.namecheap.com/support/knowledgebase/article.aspx/9605/69/how-to-check-ca-chain-installation
- /superuser/97201/how-to-save-a-remote-server-ssl-certificate-locally-as-a-file/
- Как конвертировать .crt в .pem