Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node uses an hardcoded list of certificate authorities #4175

Closed
fir4 opened this issue Dec 7, 2015 · 32 comments · Fixed by #9139
Closed

Node uses an hardcoded list of certificate authorities #4175

fir4 opened this issue Dec 7, 2015 · 32 comments · Fixed by #9139
Labels
tls Issues and PRs related to the tls subsystem.

Comments

@fir4
Copy link

fir4 commented Dec 7, 2015

I was dumbfounded when I realized that Node uses a statically compiled, manually updated, hardcoded list of certificate authorities, rather than relying on the system's trust store, or even just a directory truststore of its own.

This causes a large amount of problems :

  • Dependancy on the Node community for reactiveness in addition or removal of certificates
  • Dependancy on the Node community in terms of certificate trust
  • Prevents companies and anyone with their own PKI from using their certificates globally
  • Requires support from EVERY node application making use of SSL to include certificates
  • Requires modification of source code if an application doesn't happen to support it
  • Requires modification and rebuilding of Node to remove certificates that wouldn't be trusted by an organisation

Now, I can see no practical use for that. While this is acceptable in a development environment, where you can make changes to your own application, this is outright unusable... and i can't stress enough the security implications for many organisations.

Proposed solutions :

  • Make use of the standard system trust store, like any sensible application
  • Use a dedicated globally installed trust store, allowing user modifications, and why not, handling with npm
  • Dynamically load CAs using relative path, in a way similar to the usage of the node_modules folder

TL;DR: CA Certificates are hardcoded in node. It may be OK for dev, but it sucks big time for ops.

@saghul saghul added the tls Issues and PRs related to the tls subsystem. label Dec 7, 2015
@kapouer
Copy link
Contributor

kapouer commented Dec 9, 2015

Indeed, a distribution like debian needs to work around that using that kind of patch.

I already asked this in
#3159
I suppose a pull request could make it now ? @fir4 feels like writing one ?

@doodadjs
Copy link

doodadjs commented Dec 9, 2015

@kapouer Path should not be hard-coded. Also what for other distributions of Linux, and other OSs like Windows and OS X ? This issue requires more research

@kapouer
Copy link
Contributor

kapouer commented Dec 9, 2015

I think the simplest thing to do is to have a configurable path as a build option - so that each distributor can point nodejs to the right place where it can find the system-installed root ca(s).
I don't think it's worth the time spent to be able to change that path at runtime.

@fir4
Copy link
Author

fir4 commented Dec 9, 2015

Yeah, those were simple ideas, in case you'd want more flexibility. Using a configurable path on ./configure step would be a great start, however I have literally zero idea how Certificates are handled on MacOS and Windows...

@doodadjs
Copy link

doodadjs commented Dec 9, 2015

For Windows it's too complicated. It's not just a folder. I'm thinking of a solution... Have a download link to an automatically generated zip file with the CAs. Bundle the current version with each distribution of nodejs. Add an environment variable to nodejs to locate the CAs folder. The installer will extract CAs to a proper location and set the environment variable. For Unix-like systems, the installer may try to locate system CAs. If no installer, this will have to be done manually.

EDIT: By default, use a build option like kapouer mentionned.

@royallabs
Copy link

+1

@cpmsmith
Copy link

cpmsmith commented Jan 8, 2016

👍

@ghost
Copy link

ghost commented Jan 13, 2016

Absolutely +1

Using the systems certificates store would of cause be best.
But even that should be configurable.

A configuration option like the one used by npm (setting a caFile) would be of great help for me and presumably for most others running into problems with ca-certs.

This could be a global configuration option, an environment variable and/or a commandline param.
It should not be a compile option in my opinion - at least not without being overwriteable afterwards.

While this is acceptable in a development environment…

It may be acceptable in most development environments.
Anyhow it is absolutely not acceptable by any means in my development environment nor in some others.

We are working behind a corporate proxy with ssl scanning.
Meaning the secure connection does not exist between our machines and the internet servers but between our machines and a trusted proxy and another between that proxy and the internet servers.

This leads to absolutely unexpected behavior, for example when installing packages using npm.

While we can configure npm to accept our certificate we can not make the postinstall scripts do the same. This leads to many packages not being able to be installed properly.

This means we can not even npm install some simple grunt tasks although npm already has the option to change the trusted CAs.

@ijstokes
Copy link

This is a major issue for commercial deployment of nodejs and a major obstacle to our node based software being adopted by large organizations that have their own in-house PKI. It is also indicative of a problem with the node developers lack of understanding of the importance of doing security "right".

I am very interested in seeing this issue get resolved and if there are sensible ways I can contribute to its resolution, please someone from the NodeJS team let me know (yes, a PR, I realize, but if there is any guidance on how to put that together or other considerations/constraints...)

@bnoordhuis
Copy link
Member

It is also indicative of a problem with the node developers lack of understanding of the importance of doing security "right".

Please.

yes, a PR, I realize, but if there is any guidance on how to put that together or other considerations/constraints...

Start with reading CONTRIBUTING.md. If you still have questions afterwards, I can probably answer them.

@bkreider
Copy link

Please.

Please as in, "please fix this" or "please, it is a super good idea to hard code the list of certificate authorities? "

this is outright unusable... and i can't stress enough the security implications for many organisations.

+1.

@Fishrock123
Copy link
Contributor

Please as in, "please fix this" or "please, it is a super good idea to hard code the list of certificate authorities? "

I Think that was a "Please do not assume things".

@ghost
Copy link

ghost commented Mar 24, 2016

Please as in, "please fix this" or "please, it is a super good idea to hard code the list of certificate authorities? "

I think its more sort of "please stop being that accusing".

It is also indicative of a problem with the node developers lack of understanding of the importance of doing security "right".

I do not think they do not understand the importance to do it right.
One major problem of security is, that most people do not know, how to do it right and do not see all the problems which may arise. This is btw. a major problem in software engineering in general.

As long as no authoritys certs need to be removed, nobody outside of corporate environments with high security and compliance standards may even notice any problems with the integration as it is today. And nobody outside such environments would even think about all the problems wich will arise inside this environments.

This seems pretty much normal to me and there is no point in being harsh, accusing the developers not to try to do things right or anything alike.

Anyways, in my opinion the issue is of great importance and it needs to be fixed asap.

@bkreider
Copy link

I Think that was a "Please do not assume things".

Thank you for clarifying.

One major problem of security is, that most people do not know, how to do it right and do not see all the problems which may arise.

I agree. Thanks for taking the time to explain.

@willink
Copy link

willink commented Apr 5, 2016

We are working behind a corporate proxy with ssl scanning.
Meaning the secure connection does not exist between our machines and the internet servers but between our machines and a trusted proxy and another between that proxy and the internet servers.

This leads to absolutely unexpected behavior, for example when installing packages using npm.

While we can configure npm to accept our certificate we can not make the postinstall scripts do the same. This leads to many packages not being able to be installed properly.

I am in the exact same scenario. This is an important issue that needs a solution.

@aldahick
Copy link

Putting in my two cents: trying to write a Node application for a major university, and it's not exactly optimal with this issue.

Is anyone currently working on this? microsoft/tfs-cli#118 has a workaround, but I'd love to see the issue fixed in Node itself.

@bnoordhuis
Copy link
Member

Is anyone currently working on this?

Not that I know of. I think I speak for the project when I say that we'll review patches but that none of the collaborators feel a strong urge to work on it themselves.

@DuBistKomisch
Copy link

+1

Our product targets education environments, where MITM'ing SSL is almost standard, so this is a major problem for us. We didn't even realise this behaviour was the case until customers kept complaining their certs weren't trusted, since every other piece of software I've seen does this by default.

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

@xel-x
Copy link

xel-x commented Jul 4, 2016

I think I speak for the project when I say that we'll review patches but that none of the collaborators feel a strong urge to work on it themselves.

I guess we should stop using Node to do any serious work then.

@Fishrock123
Copy link
Contributor

Please leave the sarcasm for elsewhere; we'd gladly review a patch for this if someone were to make a pull request.

Most of us are pretty busy so we can't necessarily guarantee when this will get done if no-one steps up, though.

@xel-x
Copy link

xel-x commented Jul 4, 2016

I am sorry, it seems I didn't made clear what my point is. There was absolutely no sarcasm intended in any way.

See: As we can not influence the environments our projects need to run in, we simply can not build upon a foundation which does not cover such cases.

We had to move an entire project to a different language, as it was impossible to make it work using Node inside our clients environment.

@bnoordhuis
Copy link
Member

I don't get that attitude. You feel strongly enough to complain about it on the bug tracker, apparently strongly enough to switch to a different language but not strongly enough to spend an hour or two on a pull request. The whole point of open source is that you can change it if you don't like what it does.

@doodadjs
Copy link

doodadjs commented Jul 4, 2016

I have proposed a solution and I think it will be more productive if others do the same or make a pull request instead of just bumping the thread.

@mwain
Copy link
Contributor

mwain commented Aug 8, 2016

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.

E.g.

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

@jan-swiecki
Copy link

It turns out that https.request module with ca option doesn't support having multiple certificates in pem file. @DuBistKomisch solution solved this problem. I'm using node v4.

@SeanHayes
Copy link

Setting https.globalAgent.options.ca works for connections to my own server but causes SSL errors for regular connections (which normally work when https.globalAgent.options.ca isn't set). Is there a way to get https.globalAgent.options.ca to append to the default list of certificates used by node?

@sam-github
Copy link
Contributor

Not programmatically, but with env configuration it is: https://nodejs.org/api/cli.html#cli_node_extra_ca_certs_file

@nomanmaqsood
Copy link

nomanmaqsood commented Aug 12, 2021

@mwain just wanted to understand will https.globalAgent.options.ca.push(fs.readFileSync(ca)); override the globally trusted Nodejs certificates (the Mozilla certificates which come bundled with nodejs as default trusted CA) ?
and my second concern is will it impact some performance issue?

Looking forward to your reply

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.

E.g.

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

@TomasHubelbauer
Copy link

TomasHubelbauer commented Oct 5, 2021

Can anyone please explain something I'm not understanding about the rationale of bundling own CA store in Node as opposed to using the system CA store?

I see two reasons why Node might choose to use the Firefox's store:

  • Not have to interface with individual OS's APIs for trust stores
  • Be able to boot bad CAs in response to security-related events

I think Mozilla's reason for bundling the CA store is primarily the latter as described in this article: https://blog.mozilla.org/security/2019/02/14/why-does-mozilla-maintain-our-own-root-certificate-store

But, I do not think this applies to Node? Because since the store is bundled and Node doesn't not have a self-updater, no CA can be booted from an existing Node installation, correct? So if there was a bad CA to be removed, the Node installation at a user's server would have to be updated to the new version that removes the bad CA by updating the bundled store.

If that is the case, is the situation merely that Node bundles the Mozilla CA store so that it doesn't have to implement each OS's APIs for the trust store reading? And since --use-openssl-ca is supported, is that not kind of a moot point now? Could --use-openssl-ca be made the default? What would the downsides of that be? Is it not the default due to backcompat concerns?

Very curious to learn more about this, thank you in advance.

@ustun
Copy link

ustun commented Jan 15, 2022

since --use-openssl-ca is supported, is that not kind of a moot point now?

@TomasHubelbauer --use-openssl-ca is not supported on Windows since Windows has its own certificate store. But it might be made default elsewhere perhaps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tls Issues and PRs related to the tls subsystem.
Projects
None yet
Development

Successfully merging a pull request may close this issue.