Erro: não foi possível verificar o primeiro certificado no nodejs


141

Estou tentando baixar um arquivo do servidor jira usando um URL, mas estou recebendo um erro. como incluir o certificado no código para verificar o erro:

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)

Meu código 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);

    });
});

você foi capaz de resolver isso?
— sharad jain

1
i usado outro procedimento como desabilitar a verificação do certificado e feito
— Labeo

você pode elaborar um pouco mais? Isso vai ser realmente útil para mim
— sharad jain

veja abaixo resposta para validação de certificado precisamos ter rejectUnauthorized
— Labeo

Respostas:


120

Tente adicionar o certificado raiz apropriado

Essa sempre será uma opção muito mais segura do que aceitar cegamente pontos finais não autorizados, os quais, por sua vez, devem ser usados ​​apenas como último recurso.

Isso pode ser tão simples quanto adicionar

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

para o seu aplicativo.

O pacote npm de CAs raiz SSL (conforme usado aqui) é um pacote muito útil sobre esse problema.


9
Essa resposta deve ser usada na maioria dos casos, pois corrige o problema em vez de desabilitar todo o benefício do SSL.
— Mikemaccana

12
Conforme declarado no README do módulo ssl-root-cas, uma das causas mais comuns para esse problema é que o seu certificado não incorpora seus certificados CA intermediários. Tente consertar seu certificado antes de tentar qualquer outra coisa;);
— Laurent VB

Você pode nem precisar do pacote SSL-root-cas. Basta definir o globalAgents.option.cert como um certificado de cadeia completa. Foi isso que resolveu meu problema.
— Smartexpert

1
O mkcert não cria um certificado "fullchain". Você tem que concatenar o seu certificado com a raiz cert disponível em $(mkcert -CAROOT)/rootCA.pemum novo arquivo de certificado e fazer algo como https.globalAgent.options.ca = fs.readFileSync('fullchain.pem')See github.com/FiloSottile/mkcert/issues/76
— Frosty Z

Para a segurança, o ssl-root-casmódulo npm possui uma solicitação para o mozilla.org codificado em git.coolaj86.com/coolaj86/ssl-root-cas.js/src/branch/master/… . Provavelmente é seguro porque o Mozilla, mas parece um vetor de ataque.
— Avindra Goolcharan 14/03

60

Outro truque sujo, que tornará todos os seus pedidos inseguros:

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0

8
Isso não parece diferente da resposta de Labeo acima , tão perigosa quanto.
— Ocramot 13/12/19

4
É diferente, não requer alterações de codificação, pois a variável env pode ser definida fora do código-fonte.
— Jzacharuk 9/05/19

1
Essa resposta é perigosa. Você está desativando qualquer segurança fornecida pelo TLS.
— Flimm 12/09/19

1
Isso funcionou para mim, super útil. No meu caso, estou apenas conversando com o host local , então a segurança não é o problema.
— Mike S

Bem, de fato, apenas para testar o host local. Apenas certifique-se de removê-lo após os testes.
— Nico

44

para incapaz de verificar o primeiro certificado em nodejs rejeitar não autorizado é necessário

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

129
Essa resposta é perigosa. O outro é mais seguro.
— Mikemaccana

3
Bem, fazendo isso, você remove a segurança fornecida pelo SSL, portanto ela deve ser usada apenas para desenvolvimento.
— 22416 Sylvain

11
Não verificar os certificados significa que você não pode ter certeza da identidade da outra parte e, portanto, pode estar sujeito a um host falsificado. Mesmo que você não verifique os certificados, no entanto, ainda recebe comunicação criptografada que não pode ser (facilmente) espionada. Portanto, adicionar essa linha não "remove a segurança" do SSL nem, como outro comentarista disse, "desabilita [] todo o benefício do SSL".
— Bob Pollack

4
Desativando a verificação SSL não é uma solução para qualquer problema :-).
— siddhu

9
Isso funciona se você estiver usando a biblioteca de solicitações de nó. O que eu sou. E obrigado, resolve a minha necessidade imediata de desenvolvimento.
— Alan

29

O servidor do qual você está tentando baixar pode estar mal configurado. Mesmo que funcione no seu navegador, talvez não esteja incluindo todos os certificados públicos na cadeia necessários para a verificação de um cliente vazio em cache.

Eu recomendo verificar o site na ferramenta SSLlabs: https://www.ssllabs.com/ssltest/

Procure este erro:

A cadeia de certificados deste servidor está incompleta.

E isto:

Questões em cadeia ......... Incompleto


Recebo esse problema (problemas de cadeia ......... Incompleto) para meu certificado autorizado pela DigiCert Inc., qual é o procedimento para corrigir isso?
— Imarchuang

@imarchuang Em resumo, seu servidor precisa servir não apenas o certificado do seu domínio, mas também os certificados intermediários. Não posso incluir mais detalhes neste comentário, mas espero que seja informação suficiente para apontar na direção certa.
— Flimm

muito obrigado, nós entendemos por pentear o certificado raiz também
— imarchuang

Te agradece! Eu descobri o meu cert foi incompleta, embora ele funcionou perfeitamente no Chrome e Firefox, mas não funcionou no aplicativo de elétrons, e eu fixa-lo no lado nginx porcat domainname.crt domainname.ca-bundle > domainname-ssl-bundle.crt
— Ivan Borshchov

26

unable to verify the first certificate

A cadeia de certificados está incompleta.

Isso significa que o servidor da web ao qual você está se conectando está configurado incorretamente e não incluiu o certificado intermediário na cadeia de certificados que ele enviou a você.

Cadeia de certificados

Provavelmente tem a seguinte aparência:

  1. Certificado do servidor - armazena um certificado assinado pelo intermediário.
  2. Certificado intermediário - armazena um certificado assinado pela raiz.
  3. Certificado raiz - armazena um certificado autoassinado.

O certificado intermediário deve ser instalado no servidor, junto com o certificado do servidor.
Os certificados raiz são incorporados aos aplicativos de software, navegadores e sistemas operacionais.

O aplicativo que atende o certificado deve enviar a cadeia completa, isso significa o próprio certificado do servidor e todos os intermediários. O certificado raiz deve ser conhecido pelo cliente.

Recrie o problema

Acesse https://incomplete-chain.badssl.com usando seu navegador.

Não mostra nenhum erro (o cadeado na barra de endereço é verde).
Isso ocorre porque os navegadores tendem a completar a cadeia se não forem enviados do servidor.

Agora, conecte-se a https://incomplete-chain.badssl.com usando o 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);
  });

Logs: " Erro: não é possível verificar o primeiro certificado ".

Solução

Você precisa completar a cadeia de certificados.

Fazer isso:

1: você precisa obter o certificado intermediário ausente no .pemformato e, em seguida,

2a: estenda o armazenamento de certificados interno do Node usando NODE_EXTRA_CA_CERTS,

2b: ou passe seu próprio pacote de certificados (intermediários e raiz) usandoca opção

1. Como obtenho certificado intermediário?

Usando openssl(vem com Git para Windows ).

Salve os detalhes do certificado do servidor remoto:

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

Estamos procurando o emissor (o certificado intermediário é o emissor / assinante do certificado do servidor):

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

Ele deve fornecer o URI do certificado de assinatura. Baixe:

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

Por fim, converta-o para .pem:

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

2a NODE_EXTRA_CERTS

Estou usando o ambiente cruzado para definir variáveis ​​de ambiente no package.jsonarquivo:

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

2b. caopção

Essa opção substituirá as CAs raiz internas do Nó.

É por isso que precisamos criar nossa própria CA raiz. Use ssl-root-cas .

Em seguida, crie um httpsagente personalizado configurado com nosso pacote de certificados (raiz e intermediário). Passe este agente para axiosao fazer uma solicitação.

// 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);
  });

Em vez de criar um httpsagente personalizado e passá-lo para axios, você pode colocar os certificados no httpsagente global:

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

Recursos:

  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. Como converter .crt para .pem

Explicação muito detalhada.
— Sete

Absolutamente surpreendente! Não funcionou para mim, mas que detalhe!
— Tom Chadaravicius 26/03

6

Isso realmente resolveu para mim, em 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
Essa é a melhor solução imho, pois não requer bibliotecas adicionais e é simples
— Martin Schneider

4

Você pode fazer isso modificando as opções de solicitação conforme abaixo. Se você estiver usando um certificado autoassinado ou um intermediário ausente, configurar strictSSL como false não forçará o pacote de solicitação para validar o certificado.

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

Isso resolveu meu problema, estou usando o módulo 'request' em vez do 'http'. Obrigado!
— Bruno Nunes

2

Certificado SSL do GoDaddy

Eu experimentei isso ao tentar conectar ao nosso servidor de API back-end com certificado GoDaddy e aqui está o código que eu usei para resolver o problema.

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:

Use o certificado incluído e não esqueça de instalar a biblioteca npm install ssl-root-cas


1
isso funcionou para mim, exceto que, durante a importação, tive que usar "ssl-root-cas" em vez de "ssl-root-cas / latest".
— precisa

2

Isso funcionou para mim => adicionando agente e 'rejectUnauthorized' definido como 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

Outra abordagem para resolver isso é usar o seguinte módulo.

node_extra_ca_certs_mozilla_bundle

Este módulo pode funcionar sem nenhuma modificação de código, gerando um arquivo PEM que inclui todos os certificados raiz e intermediários confiáveis ​​pelo Mozilla. Você pode usar a seguinte variável de ambiente (Works with Nodejs v7.3 +),

NODE_EXTRA_CA_CERTS

Para gerar o arquivo PEM para usar com a variável de ambiente acima. Você pode instalar o módulo usando:

npm install --save node_extra_ca_certs_mozilla_bundle

e, em seguida, inicie o script do nó com uma variável de ambiente.

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

Outras maneiras de usar o arquivo PEM gerado estão disponíveis em:

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

NOTA: Eu sou o autor do módulo acima.


-3

Eu estava usando o módulo nodemailer npm. O código abaixo resolveu o problema

     tls: {
     // do not fail on invalid certs
     rejectUnauthorized: false
     }
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.