Erreur: impossible de vérifier le premier certificat dans nodejs

141

J'essaye de télécharger un fichier du serveur jira en utilisant une URL mais j'obtiens une erreur. comment inclure le certificat dans le code pour vérifier l' erreur:

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)

Mon code 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);

    });
});
Labeo
la source
avez-vous pu résoudre ce problème?
sharad jain
1
J'ai utilisé une autre procédure comme la désactivation de la vérification du certificat et terminé
Labeo
pouvez-vous élaborer un peu plus? Ce sera vraiment utile pour moi
sharad jain
voir ci-dessous la réponse pour la validation du certificat que nous devons avoir rejetéUnauthorized
Labeo

Réponses:

120

Essayez d'ajouter le certificat racine approprié

Ce sera toujours une option beaucoup plus sûre que d'accepter aveuglément des points d'extrémité non autorisés, qui ne devraient à leur tour être utilisés qu'en dernier recours.

Cela peut être aussi simple que d'ajouter

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

à votre application.

Le package npm des autorités de certification racine SSL (tel qu'utilisé ici) est un package très utile concernant ce problème.

Joshua
la source
9
Cette réponse doit être utilisée dans la plupart des cas car elle résout le problème plutôt que de désactiver l'ensemble des avantages de SSL.
mikemaccana
12
Comme indiqué dans le fichier README du module ssl-root-cas, l'une des causes les plus courantes de ce problème est que votre certificat n'intègre pas ses certificats CA intermédiaires. Essayez de réparer votre certificat avant d'essayer autre chose;)
Laurent VB
Vous n'avez peut-être même pas besoin du package SSL-root-cas. Définissez simplement globalAgents.option.cert sur un certificat fullchain. C'est ce qui a résolu mon problème.
smartexpert
1
mkcert ne crée pas de certificat "fullchain". Vous devez concaténer votre certificat avec le certificat racine disponible à l' adresse$(mkcert -CAROOT)/rootCA.pem dans un nouveau fichier de certificat et faire quelque chose comme https.globalAgent.options.ca = fs.readFileSync('fullchain.pem')Voir github.com/FiloSottile/mkcert/issues/76
Frosty Z
Pour les soucis de sécurité, le ssl-root-casmodule npm a une requête à mozilla.org codée en dur git.coolaj86.com/coolaj86/ssl-root-cas.js/src/branch/master/… . C'est probablement sûr parce que Mozilla mais cela semble être un vecteur d'attaque.
Avindra Goolcharan
61

Un autre hack sale, qui rendra toutes vos demandes non sécurisées:

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0
Satara
la source
8
Cela ne semble pas différent de la réponse de Labeo ci - dessus , tout aussi dangereux.
ocramot
4
C'est différent, cela ne nécessite aucune modification de codage car la variable env peut être définie en dehors du code source.
jzacharuk
1
Cette réponse est dangereuse. Vous désactivez toute sécurité fournie par TLS.
Flimm le
1
Cela a fonctionné pour moi, très utile. Dans mon cas, je parle juste à localhost , donc la sécurité n'est pas le problème.
Mike S
Bien en effet juste pour tester localhost. Assurez-vous simplement de le supprimer après vos tests.
Nico le
44

pour incapable de vérifier le premier certificat dans nodejs, rejeter non autorisé est nécessaire

 request({method: "GET", 
        "rejectUnauthorized": false, 
        "url": url,
        "headers" : {"Content-Type": "application/json",
        function(err,data,body) {
    }).pipe(
       fs.createWriteStream('file.html'));
Labeo
la source
130
Cette réponse est dangereuse. L'autre est plus sûr.
mikemaccana
3
Eh bien, en faisant cela, vous supprimez la sécurité fournie par SSL, elle ne devrait donc être utilisée que pour le développement.
Sylvain
11
Ne pas vérifier les certificats signifie que vous ne pouvez pas être certain de l'identité de l'autre partie et que vous pourriez donc être soumis à un hôte usurpé. Même si vous ne vérifiez pas les certificats, vous obtenez toujours une communication cryptée qui ne peut pas être (facilement) espionnée. Donc, ajouter cette ligne ne "supprime pas la sécurité" de SSL ni, comme un autre commentateur l'a dit, "désactiver [] tous les avantages de SSL".
Bob Pollack
4
La désactivation de la vérification SSL n'est PAS une solution à aucun problème. :-)
Siddhu
9
Cela fonctionne si vous utilisez la bibliothèque de requêtes de nœuds. Ce que je suis. Et merci, cela résout mon besoin immédiat de développement.
Alan
29

Le serveur à partir duquel vous essayez de télécharger est peut-être mal configuré. Même si cela fonctionne dans votre navigateur, il se peut qu'il n'inclue pas tous les certificats publics de la chaîne nécessaires à un client vide de cache.

Je recommande de vérifier le site dans l'outil SSLlabs: https://www.ssllabs.com/ssltest/

Recherchez cette erreur:

La chaîne de certificats de ce serveur est incomplète.

Et ça:

Problèmes de chaîne ......... Incomplet

Flimm
la source
J'obtiens ce problème (problèmes de chaîne ......... incomplet) pour mon certificat qui est autorisé par DigiCert Inc., quelle est la procédure pour résoudre ce problème?
imarchuang
@imarchuang En bref, votre serveur doit servir non seulement le certificat de votre domaine, mais également les certificats intermédiaires. Je ne peux pas donner plus de détails dans ce commentaire, mais j'espère que ce sont suffisamment d'informations pour vous orienter dans la bonne direction.
Flimm
merci beaucoup, nous avons compris en peignant aussi le certificat racine
imarchuang
Merci! J'ai découvert que mon certificat était incomplet, même s'il fonctionnait parfaitement dans Chrome et Firefox, mais ne fonctionnait pas dans l'application Electron, et je l'ai corrigé sur nginx côte à côtecat domainname.crt domainname.ca-bundle > domainname-ssl-bundle.crt
Ivan Borshchov
26

unable to verify the first certificate

La chaîne de certificats est incomplète.

Cela signifie que le serveur Web auquel vous vous connectez est mal configuré et n'inclut pas le certificat intermédiaire dans la chaîne de certificats qu'il vous a envoyé.

Chaîne de certificats

Cela ressemble très probablement à ceci:

  1. Certificat de serveur - stocke un certificat signé par l'intermédiaire.
  2. Certificat intermédiaire - stocke un certificat signé par root.
  3. Certificat racine - stocke un certificat auto-signé.

Le certificat intermédiaire doit être installé sur le serveur, avec le certificat du serveur.
Les certificats racines sont intégrés aux applications logicielles, aux navigateurs et aux systèmes d'exploitation.

L'application servant le certificat doit envoyer la chaîne complète, c'est-à-dire le certificat du serveur lui-même et tous les intermédiaires. Le certificat racine est censé être connu du client.

Recréez le problème

Accédez à https://incomplete-chain.badssl.com en utilisant votre navigateur.

Il ne montre aucune erreur (le cadenas dans la barre d'adresse est vert).
C'est parce que les navigateurs ont tendance à compléter la chaîne si elle n'est pas envoyée depuis le serveur.

Maintenant, connectez-vous à https://incomplete-chain.badssl.com en utilisant 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);
  });

Journaux: " Erreur: impossible de vérifier le premier certificat ".

Solution

Vous devez compléter la chaîne de certificats vous-même.

Pour faire ça:

1: Vous devez obtenir le certificat intermédiaire manquant au .pemformat, puis

2a: étendre le magasin de certificats intégré de Node en utilisant NODE_EXTRA_CA_CERTS,

2b: ou passez votre propre bundle de certificats (intermédiaires et racine) en utilisant l' caoption.

1. Comment obtenir un certificat intermédiaire?

Utilisation de openssl(livré avec Git pour Windows ).

Enregistrez les détails du certificat du serveur distant:

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

Nous recherchons l'émetteur (le certificat intermédiaire est l'émetteur / signataire du certificat serveur):

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

Il devrait vous donner l'URI du certificat de signature. Télécharge le:

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

Enfin, convertissez-le en .pem:

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

2a. NODE_EXTRA_CERTS

J'utilise cross-env pour définir les variables d'environnement dans le package.jsonfichier:

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

2b. caoption

Cette option va écraser les autorités de certification racine intégrées du nœud.

C'est pourquoi nous devons créer notre propre autorité de certification racine. Utilisez ssl-root-cas .

Ensuite, créez un httpsagent personnalisé configuré avec notre bundle de certificats (racine et intermédiaire). Transmettez cet agent à axioslors de la demande.

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

Au lieu de créer un httpsagent personnalisé et de le transmettre à axios, vous pouvez placer les certifcats sur l' httpsagent global:

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

Ressources:

  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. Comment convertir .crt en .pem
sch
la source
Explication très détaillée.
Sept
1
Absolument incroyable! Cela n'a pas fonctionné pour moi, mais quel détail!
Tom Chadaravicius
6

Cela a en fait résolu le problème pour moi, sur 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
});
Koolaang
la source
1
C'est la meilleure solution à mon avis, car elle ne nécessite pas de bibliothèques supplémentaires et est simple
Martin Schneider
4

Vous pourrez peut-être le faire en modifiant les options de demande comme ci-dessous. Si vous utilisez un certificat auto-signé ou un intermédiaire manquant, la définition de strictSSL sur false ne forcera pas le package de requête à valider le certificat.

var options = {
   host: 'jira.example.com',
   path: '/secure/attachment/206906/update.xlsx',
   strictSSL: false
}
Sundar
la source
Cela a résolu mon problème, j'utilise le module 'request' au lieu du 'http'. Merci!
Bruno Nunes
2

Certificat CC GoDaddy SSL

J'ai vécu cela en essayant de me connecter à notre serveur API backend avec un certificat GoDaddy et voici le code que j'ai utilisé pour résoudre le problème.

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:

Utilisez le certificat fourni et n'oubliez pas d'installer la bibliothèque npm install ssl-root-cas

Dean Christian Armada
la source
1
cela a fonctionné pour moi sauf que lors de l'importation, j'ai dû utiliser "ssl-root-cas" au lieu de "ssl-root-cas / latest".
krishnan
2

Cela a fonctionné pour moi => ajout d'un agent et "rejeter non autorisé" défini sur faux

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

Vigneshwaran Ethirajan
la source
1

Une autre approche pour résoudre ce problème consiste à utiliser le module suivant.

node_extra_ca_certs_mozilla_bundle

Ce module peut fonctionner sans aucune modification de code en générant un fichier PEM qui comprend tous les certificats racine et intermédiaires approuvés par Mozilla. Vous pouvez utiliser la variable d'environnement suivante (Fonctionne avec Nodejs v7.3 +),

NODE_EXTRA_CA_CERTS

Pour générer le fichier PEM à utiliser avec la variable d'environnement ci-dessus. Vous pouvez installer le module en utilisant:

npm install --save node_extra_ca_certs_mozilla_bundle

puis lancez votre script de nœud avec une variable d'environnement.

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

D'autres façons d'utiliser le fichier PEM généré sont disponibles sur:

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

REMARQUE: je suis l'auteur du module ci-dessus.

arva
la source
-3

J'utilisais le module nodemailer npm. Le code ci-dessous a résolu le problème

     tls: {
     // do not fail on invalid certs
     rejectUnauthorized: false
     }
Chandru
la source