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.