Errore: impossibile verificare il primo certificato in nodejs


141

Sto provando a scaricare un file dal server jira usando un url ma sto ricevendo un errore. come includere il certificato nel codice per verificare l' errore:

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)

Il mio codice 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);

    });
});

sei riuscito a risolverlo?
Sharad jain,

1
ho usato un'altra procedura come disabilitare la verifica del certificato e fatto
Labeo,

puoi approfondire un po 'di più? Questo sarà davvero utile per me
sharad jain,

vedi sotto la risposta per la convalida del certificato che dobbiamo avere rifiutato Non autorizzato
Labeo

Risposte:


120

Prova ad aggiungere il certificato radice appropriato

Questa sarà sempre un'opzione molto più sicura rispetto all'accettazione cieca di punti finali non autorizzati, che a loro volta dovrebbero essere usati solo come ultima risorsa.

Questo può essere semplice come aggiungere

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

alla tua applicazione.

Il pacchetto npm di CA radice SSL (come utilizzato qui) è un pacchetto molto utile per quanto riguarda questo problema.


9
Questa risposta dovrebbe essere utilizzata nella maggior parte dei casi poiché risolve effettivamente il problema anziché disabilitare l'intero vantaggio di SSL.
Mikemaccana,

12
Come indicato nel modulo README ssl-root-cas, una delle cause più comuni di questo problema è che il certificato non incorpora i certificati CA intermedi. Prova a correggere il certificato prima di provare qualcos'altro;)
Laurent VB,

Potrebbe non essere necessario nemmeno il pacchetto SSL-root-cas. Basta impostare globalAgents.option.cert su un certificato fullchain. Questo è ciò che ha risolto il mio problema.
smartexpert

1
mkcert non crea un certificato "fullchain". Devi concatenare il tuo certificato con il certificato root disponibile in $(mkcert -CAROOT)/rootCA.pemin un nuovo file di certificato e fare qualcosa come https.globalAgent.options.ca = fs.readFileSync('fullchain.pem')See github.com/FiloSottile/mkcert/issues/76
Frosty Z

Per la sicurezza, il ssl-root-casmodulo npm ha una richiesta a mozilla.org hardcoded git.coolaj86.com/coolaj86/ssl-root-cas.js/src/branch/master/… . Probabilmente è sicuro perché Mozilla ma sembra un vettore di attacco.
Avindra Goolcharan,

61

Un altro trucco sporco, che renderà insicure tutte le tue richieste:

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0

8
Questo non sembra diverso dalla risposta di Labeo sopra , come altrettanto pericoloso.
Ocramot,

4
È diverso, non richiede modifiche al codice poiché la variabile env può essere impostata al di fuori del codice sorgente.
jzacharuk,

1
Questa risposta è pericolosa. Stai disabilitando qualsiasi sicurezza fornita da TLS.
Flimm,

1
Questo ha funzionato per me, molto utile. Nel mio caso, sto solo parlando con localhost , quindi la sicurezza non è il problema.
Mike S,

Bene davvero solo per testare localhost. Assicurati di rimuoverlo dopo i test.
Nico,

44

perché non è possibile verificare che il primo certificato in nodejs sia rifiutato non autorizzato è necessario

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

130
Questa risposta è pericolosa. L'altro è più sicuro.
Mikemaccana,

3
Bene, facendo ciò, rimuovi la sicurezza fornita da SSL, quindi dovrebbe essere usata solo per lo sviluppo.
Sylvain,

11
Non controllare i certificati significa che non si può essere certi dell'identità dell'altra parte e quindi si potrebbe essere soggetti a un host contraffatto. Anche se non controlli i certificati, ricevi comunque comunicazioni crittografate che non possono essere (facilmente) spiate. Quindi aggiungere questa riga non "rimuove la sicurezza" di SSL né, come ha detto un altro commentatore "disabilitare [] l'intero vantaggio di SSL".
Bob Pollack,

4
La disabilitazione della verifica SSL NON è una soluzione a nessun problema. :-)
Siddhu,

9
Funziona se si utilizza la libreria di richieste del nodo. Che io sono. E grazie, risolve il mio immediato bisogno di sviluppo.
Alan,

29

Il server da cui stai tentando di scaricare potrebbe non essere configurato correttamente. Anche se funziona nel tuo browser, potrebbe non includere tutti i certificati pubblici nella catena necessari per la verifica di un client vuoto nella cache.

Consiglio di controllare il sito nello strumento SSLlabs: https://www.ssllabs.com/ssltest/

Cerca questo errore:

La catena di certificati di questo server è incompleta.

E questo:

Problemi di catena ......... incompleti


Ottengo questo problema (problemi di catena ......... incompleti) per il mio certificato che è autorizzato da DigiCert Inc., qual è la procedura per risolvere questo problema?
imarchuang,

@imarchuang In breve, il tuo server deve servire non solo il certificato per il tuo dominio, ma anche i certificati intermedi. Non posso inserire più dettagli in questo commento, ma spero che siano sufficienti informazioni per indicarti la giusta direzione.
Flimm,

grazie mille, abbiamo capito anche pettinando la radice della radice
imarchuang,

Grazie! Ho scoperto che il mio certificato era incompleto, sebbene funzionasse perfettamente in Chrome e Firefox ma non funzionasse nell'app per elettroni, e l'ho risolto sul lato nginx dicat domainname.crt domainname.ca-bundle > domainname-ssl-bundle.crt
Ivan Borshchov il

26

unable to verify the first certificate

La catena di certificati è incompleta.

Significa che il server web a cui ci si sta connettendo non è configurato correttamente e non ha incluso il certificato intermedio nella catena di certificati che ti è stato inviato.

Catena di certificati

Molto probabilmente appare come segue:

  1. Certificato server: memorizza un certificato firmato da intermedio.
  2. Certificato intermedio: memorizza un certificato firmato da root.
  3. Certificato radice: memorizza un certificato autofirmato.

Il certificato intermedio deve essere installato sul server, insieme al certificato del server.
I certificati di root sono integrati nelle applicazioni software, nei browser e nei sistemi operativi.

L'applicazione che serve il certificato deve inviare la catena completa, ciò significa che il certificato del server stesso e tutti gli intermedi. Il certificato radice dovrebbe essere conosciuto dal client.

Ricrea il problema

Vai su https://incomplete-chain.badssl.com usando il tuo browser.

Non mostra alcun errore (il lucchetto nella barra degli indirizzi è verde).
È perché i browser tendono a completare la catena se non viene inviato dal server.

Ora connettiti a https://incomplete-chain.badssl.com usando 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);
  });

Registri: " Errore: impossibile verificare il primo certificato ".

Soluzione

Devi completare tu stesso la catena di certificati.

Fare quello:

1: È necessario ottenere il certificato intermedio mancante in .pemformato, quindi

2a: estendi l'archivio certificati incorporato di Node usando NODE_EXTRA_CA_CERTS,

2b: oppure passare il proprio pacchetto di certificati (intermedi e root) utilizzando l' caopzione.

1. Come posso ottenere un certificato intermedio?

Utilizzo openssl(viene fornito con Git per Windows ).

Salvare i dettagli del certificato del server remoto:

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

Stiamo cercando l'emittente (il certificato intermedio è l'emittente / firmatario del certificato del server):

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

Dovrebbe fornirti l'URI del certificato di firma. Scaricalo:

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

Infine, convertilo in .pem:

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

2a. NODE_EXTRA_CERTS

Sto usando cross-env per impostare le variabili di ambiente nel package.jsonfile:

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

2b. caopzione

Questa opzione sovrascriverà le CA root incorporate del nodo.

Ecco perché dobbiamo creare la nostra CA principale. Usa ssl-root-cas .

Quindi, crea un httpsagente personalizzato configurato con il nostro pacchetto di certificati (root e intermedio). Passare questo agente a axiosquando si effettua la richiesta.

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

Invece di creare un httpsagente personalizzato e passarlo a axios, è possibile posizionare i certificati sull'agente httpsglobale:

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

risorse:

  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. Come convertire .crt in .pem

Spiegazione molto dettagliata.
Sette

1
Assolutamente fantastico! Non ha funzionato per me, ma che dettaglio!
Tom Chadaravicius il

6

Questo in realtà lo ha risolto per me, da 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
Questa è la migliore soluzione imho, in quanto non richiede librerie aggiuntive ed è semplice
Martin Schneider,

4

Potrebbe essere possibile farlo modificando le opzioni di richiesta come di seguito. Se si utilizza un certificato autofirmato o un intermediario mancante, l'impostazione di strictSSL su false non imporrà un pacchetto di richiesta per convalidare il certificato.

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

Questo ha risolto il mio problema, sto usando il modulo 'request' invece di 'http'. Grazie!
Bruno Nunes,

2

Certificato SSL GoDaddy

L'ho provato mentre provavo a connettermi al nostro server API back-end con il certificato GoDaddy ed ecco il codice che ho usato per risolvere il 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:

Usa il certificato in bundle e non dimenticare di installare la libreria npm install ssl-root-cas


1
questo ha funzionato per me tranne che durante l'importazione ho dovuto usare "ssl-root-cas" invece di "ssl-root-cas / latest".
Krishnan,

2

Questo ha funzionato per me => aggiungendo l'agente e 'rejectUnauthorized' impostato su 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

Un altro approccio per risolvere questo è quello di utilizzare il seguente modulo.

node_extra_ca_certs_mozilla_bundle

Questo modulo può funzionare senza alcuna modifica del codice generando un file PEM che include tutti i certificati root e intermedi considerati affidabili da Mozilla. È possibile utilizzare la seguente variabile di ambiente (funziona con Nodejs v7.3 +),

NODE_EXTRA_CA_CERTS

Per generare il file PEM da utilizzare con la variabile di ambiente sopra. È possibile installare il modulo utilizzando:

npm install --save node_extra_ca_certs_mozilla_bundle

e quindi avvia lo script del nodo con una variabile di ambiente.

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

Altri modi per utilizzare il file PEM generato sono disponibili su:

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

NOTA: sono l'autore del modulo sopra.


-3

Stavo usando il modulo npm di nodemailer. Il codice seguente ha risolto il problema

     tls: {
     // do not fail on invalid certs
     rejectUnauthorized: false
     }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.