How to add custom certificate authority (CA) to nodejs

前端 未结 5 1059
失恋的感觉
失恋的感觉 2020-11-29 02:03

I\'m using a CLI tool to build hybrid mobile apps which has a cool upload feature so I can test the app on a device without going through the app store (it\'s ionic-cli). Ho

相关标签:
5条回答
  • 2020-11-29 02:11

    There is an undocumented, seemingly stable, API for appending a certificate to the default list:

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

    For more information, checkout the open issue on the subject: https://github.com/nodejs/node/issues/27079

    0 讨论(0)
  • 2020-11-29 02:16

    Node.js 7.3.0 (and the LTS versions 6.10.0 and 4.8.0) added NODE_EXTRA_CA_CERTS environment variable for you to pass the CA certificate file. It will be safer than disabling certificate verification using NODE_TLS_REJECT_UNAUTHORIZED.

    $ export NODE_EXTRA_CA_CERTS=[your CA certificate file path]
    
    0 讨论(0)
  • 2020-11-29 02:16

    This is not currently possible unless you compile a custom version of nodejs with custom CA certs. Hard-baked CA certs is a current limitation of nodejs until someone submits a PR and it's merged. It's a problem for others as well.

    Below I have some copies of workarounds which might help some people but probably not the OP.

    As far as I know OP can:

    • Custom compile nodejs
    • submit a PR for nodejs to fix the issue
    • file an issue or PR with ionic-cli to support custom CA certs: https://github.com/driftyco/ionic-cli (as suggested by @Nate)
    • Force less security (no TLS or silence verification also suggested by @Nate)

    Others, if you control the nodejs app in question you have more options. You can of course specify the ca cert in each request. Some clever people have shared some workarounds in the github issue https://github.com/nodejs/node/issues/4175. I haven't tried any of these myself yet so no promises, I'm just sharing what I've read.

    DuBistKomisch explains how to get nodejs to use the operating system's CA certs:

    My workaround is to load and parse the system CA certs manually. Then, as recommended by the request docs, pass them in with the ca option everywhere we make a request. I presume you could also just set ca on the global agent if that works for your use case.

    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 explains how to set the CA certs globally and not on each https request:

    Had similar issues with this, have internal apps using an internally signed cert. Opted to use https.globalAgent and set an array of CA's which are defined in a config and updated on an env basis.

    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));
    }
    
    0 讨论(0)
  • 2020-11-29 02:31

    This answer is more focused towards package maintainers/builders.

    One can use this method if you do not want end users to rely on additional environment variables.

    When nodejs is built from source, it (by default, can be overridden) embeds the Mozilla CA certificate database into the binary itself. One can add more certificates to this database using the following commands:

    # Convert your PEM certificate to DER
    openssl x509 -in /path/to/your/CA.pem -outform der -out CA.der
    
    # Add converted certificate to certdata
    nss-addbuiltin -n "MyCompany-CA" -t "CT,C,C" < CA.der >> tools/certdata.txt
    
    # Regenerate src/node_root_certs.h header file
    perl tools/mk-ca-bundle.pl
    
    # Finally, compile
    make install
    
    0 讨论(0)
  • 2020-11-29 02:37

    I'm aware of two npm modules that handle this problem when you control the app:

    1. https://github.com/capriza/syswide-cas (I'm the author of this one)
    2. https://github.com/coolaj86/node-ssl-root-cas

    node-ssl-root-cas bundles it's own copies of nodes root CAs and also enables adding your own CAs to trust. It places the certs on the https global agent, so it will only be used for https module, not pure tls connections. Also, you will need extra steps if you use a custom Agent instead of the global agent.

    syswide-cas loads certificates from pre-defined directories (such as /etc/ssl/certs) and uses node internal API to add them to the trusted list of CAs in conjunction to the bundled root CAs. There is no need to use the ca option since it makes the change globally which affects all later TLS calls automatically. It's also possible to add CAs from other directories/files if needed. It was verified to work with node 0.10, node 5 and node 6.

    Since you do not control the app you can create a wrapper script to enable syswide-cas (or node-ssl-root-cas) and then require the ionic-cli script:

    require('syswide-cas'); // this adds your custom CAs in addition to bundled CAs
    require('./path/to/real/script'); // this runs the actual script
    
    0 讨论(0)
提交回复
热议问题