Node.js 如何向nodejs添加自定义证书颁发机构(CA)

Node.js 如何向nodejs添加自定义证书颁发机构(CA),node.js,npm,Node.js,Npm,我正在使用CLI工具构建混合移动应用程序,它有一个很酷的上传功能,因此我可以在设备上测试应用程序,而无需通过应用商店(它是ionic CLI)。然而,在我的公司,像许多其他公司一样,TLS请求使用公司自己的自定义CA证书重新签名,我在我的机器上的密钥链(OS X)中拥有该证书。但是,nodejs不使用密钥链获取其信任的CA列表。我不控制ionic cli应用程序,因此我不能简单地将{ca:}属性传递给https模块。我也可以看到这是一个问题,任何节点的应用程序,我不控制。可以告诉nodejs信任

我正在使用CLI工具构建混合移动应用程序,它有一个很酷的上传功能,因此我可以在设备上测试应用程序,而无需通过应用商店(它是ionic CLI)。然而,在我的公司,像许多其他公司一样,TLS请求使用公司自己的自定义CA证书重新签名,我在我的机器上的密钥链(OS X)中拥有该证书。但是,nodejs不使用密钥链获取其信任的CA列表。我不控制ionic cli应用程序,因此我不能简单地将{ca:}属性传递给https模块。我也可以看到这是一个问题,任何节点的应用程序,我不控制。可以告诉nodejs信任CA吗


我不确定这是否属于信息安全或任何其他交换…

除非您使用自定义CA证书编译自定义版本的nodejs,否则目前不可能做到这一点。在有人提交PR并将其合并之前,硬烘焙CA证书是NodeJ的当前限制。这对其他人来说也是个问题

下面我有一些变通方法的副本,可能对一些人有所帮助,但可能不是OP

据我所知,OP可以:

  • 自定义编译节点
  • 为nodejs提交PR以解决问题
  • 向ionic cli提交问题或PR以支持自定义CA证书:(由@Nate建议)
  • 强制安全(无TLS或沉默验证也由@Nate建议)
其他的,如果你控制有问题的nodejs应用,你有更多的选择。当然,您可以在每个请求中指定ca证书。一些聪明人在github问题上分享了一些解决方法。我自己还没有尝试过这些,所以没有承诺,我只是分享我读过的东西

DuBistKomisch解释了如何让NodeJ使用操作系统的CA证书:

我的解决方法是手动加载和解析系统CA证书。那么, 按照请求文档的建议,使用ca选项传递它们 我们到处提出要求。我想你也可以设置ca 全局代理,如果它适用于您的用例

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解释了如何全局设置CA证书,而不是针对每个https请求:

有类似的问题,有内部应用程序使用 签名证书。选择使用https.globalAgent并设置CA的数组 在配置中定义,并在环境基础上更新

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

我知道有两个npm模块在您控制应用程序时处理此问题:

  • (我是这本书的作者)
  • 节点ssl根CA
    绑定节点根CA的自身副本,还支持将自己的CA添加到信任中。它将证书放在https全局代理上,因此它将仅用于https模块,而不是纯tls连接。此外,如果使用自定义代理而不是全局代理,则需要额外的步骤

    syswide CA
    从预定义的目录(如/etc/ssl/certs)加载证书,并使用节点内部API将它们添加到CA的受信任列表中,与绑定的根CA一起使用。无需使用
    ca
    选项,因为它会全局更改,从而自动影响所有后续TLS调用。 如果需要,还可以从其他目录/文件添加CA。 经验证,它可用于节点0.10、节点5和节点6

    由于您不控制应用程序,因此可以创建一个包装器脚本来启用
    系统范围cas
    (或
    节点ssl根cas
    ),然后需要IONAL cli脚本:

    require('syswide-cas'); // this adds your custom CAs in addition to bundled CAs
    require('./path/to/real/script'); // this runs the actual script
    
    Node.js 7.3.0(以及LTS版本6.10.0和4.8.0)为您添加了环境变量以传递CA证书文件。这比使用
    节点\u TLS\u拒绝\u未经授权的
    禁用证书验证更安全

    $ export NODE_EXTRA_CA_CERTS=[your CA certificate file path]
    

    有一个未记录的、看似稳定的API,用于将证书附加到默认列表中:

    const tls=require('tls');
    const secureContext=tls.createSecureContext();
    // https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt
    secureContext.context.addCACert(`-----开始证书-----
    MIIEKJCCA3QGAWIBAGIQCGFBQGAAAVOFC2OLHEYNCDANBKQHKIG9W0BAQSFADA/
    MSQWIGYDVQKEXTEAWDPFSFNPZ25HDHVYZSBUCNVZDBBY4xFZAVBGNVBAMT
    DKRTVCBSB290IENBIGZMB4XDETE2MDMXNZE2NDA0NLOXDTIXMDMXNZE2NDA0NLOW
    Sjelmakga1ebhmcvmxfjaubgnbaotduxldcdzievuy3j5chqxizahbgnvbamt
    GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
    AQ8AMiIBCGKCAQEANNMM8FRLLKE3CL03G7NOYZDQ1ZUMGSHVB418XCSL7E4S0EF
    Q6MENQHY7LEQXGIHC6PJDETM86DICBP5GWA15GaN/PQeGdxyGkOlZHP/uaZ6WA8
    SMx+YK13EISDRXTA67NSHJCAHJYSE6CF6S5K671B5TAYUCV9BTYWAN8JKKQDIZ0
    Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
    a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/ONKXE00TNVJJ
    /PIZARK5MCWVXI0NHWQWM6R6HCM21AVA2H3DKWIDAKABO4IBFTCCAXKWEGYDVR0T
    AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
    CCSGAQUFBZABIZODHRWOI8VAXNYZY50CNVZDGLKLM9JC3UAWRLBNRYDXN0LMNV
    BTA7BGGRBGEFBQCWAOYVAHR0CDOVL2FWCWCHMUAWRLBNYDXN0LMNVBS9YB290CY9K
    c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
    VAYDVR0GBE0WSZAIBGZNGQWBAGEEWPWYLKWYBBAGC3XMBAQEWMDAUBGGRBGEFBQCC
    ARYAHR0CDOVL2NWCY5YB290LXGXLMXLDHNLBMNYEXB0LM9YZZA8BGNVHR8ENTAZ
    MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
    Y3JSMB0GA1UDGQWBBSOSMPJBH3DUUBROBEMRWXV86JSOTANBGQHKIG9W0BAQSF
    AAOCAQEA3TPXEfNjWDjdGBX7CVW+DLA5CEILAUCNE8IKCJLXWH9KEIK3JHRHGJO
    uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
    WAPIVJSWTMVI4MFU5AMQRSDE6EA73MJ2TCMYO5JMD6JMEWUK8SO/joWUoHOUgwu
    X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
    PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
    KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
    -----结束证书------`);
    const sock=tls.connect(443,'host',{secureContext});
    

    有关更多信息,请查看关于以下主题的公开问题:

    此答案更侧重于包维护者/构建者

    如果您不希望最终用户重新注册,则可以使用此方法
    # 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
    
    node --use-openssl-ca
    
    NODE_OPTIONS=--use-openssl-ca