web-dev-qa-db-fra.com

Comment ajouter une autorité de certification personnalisée à nodejs

J'utilise un outil CLI pour créer des applications mobiles hybrides dotées d'une fonctionnalité de téléchargement intéressante, ce qui me permet de tester l'application sur un appareil sans passer par le magasin d'applications (c'est ionic-cli). Toutefois, dans mon entreprise, comme dans bien d'autres entreprises, les demandes TLS sont re-signées avec le certificat CA personnalisé de l'entreprise, que j'ai sur ma machine dans le trousseau (OS X). Cependant, nodejs n'utilise pas le trousseau pour obtenir la liste des autorités de certification à qui faire confiance. Je ne contrôle pas l'application ionic-cli, je ne peux donc pas simplement transmettre une propriété {ca:} au module https. Je pouvais aussi voir que c'était un problème pour n'importe quelle application de noeud que je ne contrôlais pas. Est-il possible de dire à nodejs de faire confiance à une autorité de certification?

Je ne savais pas si cela appartenait à la sécurité de l'information ou à l'un des autres échanges ...

28
Mike Haas

Node.js 7.3.0 (et les versions LTS 6.10.0 et 4.8.0) ont ajouté la variable NODE_EXTRA_CA_CERTS pour que vous puissiez transmettre le fichier de certificat de l'autorité de certification. Ce sera plus sûr que de désactiver la vérification du certificat en utilisant NODE_TLS_REJECT_UNAUTHORIZED.

$ export NODE_EXTRA_CA_CERTS=[your CA certificate file path]
48
Cheng-Lin Tsao

Edit: Veuillez noter qu’il n’est pas prudent de contourner l’option ca! Cela vous laisse ouvert à une attaque de personne au milieu.


Réponse précédente:

Étant donné que vous ne contrôlez pas l'application et que vous ne pouvez pas passer l'option ca (comme d'habitude), vous pouvez essayer de dire à Node de ne pas vérifier les certificats, en définissant la variable d'environnement NODE_TLS_REJECT_UNAUTHORIZED. Par exemple:

$ export NODE_TLS_REJECT_UNAUTHORIZED=0

Puis lancez l'application.

Comme @keinabel le dit, lorsque vous faites cela, l'application fait confiance à tout certificat (usurpé, fictif, légitime), vous ouvrant ainsi à des attaques de type "personne du milieu". La solution correcte et sûre consiste pour les développeurs d'applications à vous permettre de spécifier une autorité de certification approuvée.

5
Nate

Je connais deux modules npm qui traitent ce problème lorsque vous contrôlez l'application:

  1. https://github.com/capriza/syswide-cas (je suis l'auteur de celui-ci)
  2. https://github.com/coolaj86/node-ssl-root-cas

node-ssl-root-cas regroupe ses propres copies des nœuds d'autorités de certification racine et permet également l'ajout de vos propres autorités de certification à approuver. Il place les certificats sur l'agent global https, de sorte qu'il ne sera utilisé que pour le module https et non pour les connexions tls pures. En outre, vous aurez besoin d'étapes supplémentaires si vous utilisez un agent personnalisé au lieu de l'agent global.

syswide-cas charge les certificats à partir de répertoires prédéfinis (tels que/etc/ssl/certs) et utilise l'API interne du nœud pour les ajouter à la liste approuvée des autorités de certification conjointement avec les autorités de certification racines incluses. Il n'est pas nécessaire d'utiliser l'option ca car elle effectue la modification de manière globale, ce qui affecte automatiquement tous les appels TLS ultérieurs . Il est également possible d'ajouter des autorités de certification à partir d'autres répertoires/fichiers si nécessaire. Il a été vérifié de travailler avec le noeud 0.10, le noeud 5 et le noeud 6.

Puisque vous ne contrôlez pas l'application, vous pouvez créer un script wrapper pour activer syswide-cas (ou node-ssl-root-cas), puis demander le script ionic-cli:

require('syswide-cas'); // this adds your custom CAs in addition to bundled CAs
require('./path/to/real/script'); // this runs the actual script
5
fujifish

Cela n’est actuellement pas possible, sauf si vous compilez une version personnalisée de nodejs avec des certificats CA personnalisés. Les certificats de certification automatisés sont une limitation actuelle de nodejs jusqu'à ce que quelqu'un soumette un PR et qu'il soit fusionné. C'est un problème pour les autres aussi.

Ci-dessous, j'ai quelques copies de solutions de contournement qui pourraient aider certaines personnes, mais probablement pas le PO.

Autant que je sache, OP peut:

  • Nœud de compilation personnalisé
  • soumettre un PR pour que nodejs résolve le problème
  • déposez un problème ou une relation avec ionic-cli pour prendre en charge les certificats personnalisés CA: https://github.com/driftyco/ionic-cli (comme suggéré par @Nate)
  • Forcer moins de sécurité (pas de vérification TLS ou de silence également suggérée par @Nate)

D'autres, si vous contrôlez l'application nodejs en question, vous avez plus d'options. Vous pouvez bien sûr spécifier le certificat de sécurité dans chaque demande. Certaines personnes intelligentes ont partagé certaines solutions de contournement dans le problème github https://github.com/nodejs/node/issues/4175 . Je n'ai pas encore essayé moi-même, donc aucune promesse. Je ne fais que partager ce que j'ai lu.

DuBistKomisch explique comment faire en sorte que nodejs utilise les certificats de certification du système d’exploitation:

Ma solution consiste à charger et à analyser manuellement les certificats de l'autorité de certification du système. Ensuite, comme recommandé par les documents de requête, transmettez-les avec l'option ca partout où nous faisons une demande. Je présume que vous pourriez aussi simplement activer ca l'agent global si cela fonctionne pour votre cas d'utilisation.

fs.readFileSync('/etc/ssl/certs/ca-certificates.crt')
  .toString()
  .split(/-----END CERTIFICATE-----\n?/)
  // may include an extra empty string at the end
  .filter(function (cert) { return cert !== ''; })
  // effectively split after delimiter by adding it back
  .map(function (cert) { return cert + '-----END CERTIFICATE-----\n'; })

mwain explique comment définir les certificats d’autorité de certification globalement et non sur chaque requête https:

Avait des problèmes similaires avec cela, ont des applications internes utilisant un interne cert. signé Nous avons choisi d'utiliser https.globalAgent et de définir un tableau des autorités de certification qui sont définis dans une configuration et mis à jour sur une base env.

const trustedCa = [
    '/etc/pki/tls/certs/ca-bundle.crt',
    '/path/to/custom/cert.crt'
];

https.globalAgent.options.ca = [];
for (const ca of trustedCa) {
    https.globalAgent.options.ca.Push(fs.readFileSync(ca));
}
4
chrishiestand

Il existe une API apparemment sans papiers et non documentée pour ajouter un certificat à la liste par défaut:

const tls = require('tls');

const secureContext = tls.createSecureContext();

// https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt
secureContext.context.addCACert(`-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----`);

const sock = tls.connect(443, 'Host', {secureContext});
1
Cameron Tacklind