Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
115 views
in Technique[技术] by (71.8m points)

How to fix SSL certificate error when running Npm on Windows?

When I try to install a package with npm, it doesn't work. After a long wait, I eventually get an error 'tunneling socket could not be established, sutatusCode=403'.

$ npm install coffee-script
npm http GET https://registry.npmjs.org/coffee-script
npm http GET https://registry.npmjs.org/coffee-script
npm http GET https://registry.npmjs.org/coffee-script
npm ERR! Error: tunneling socket could not be established, sutatusCode=403
npm ERR!     at ClientRequest.onConnect (c:Program Files
odejs
ode_modules
pm
ode_modules
equestunnel.js:148:19)
npm ERR!     at ClientRequest.g (events.js:193:14)
npm ERR!     at ClientRequest.EventEmitter.emit (events.js:123:20)
npm ERR!     at Socket.socketOnData (http.js:1393:11)
npm ERR!     at TCP.onread (net.js:403:27)

However, when I browse to that same URL in my web browser (Google Chrome) it loads fine (see footnote). https://registry.npmjs.org/coffee-script

What's going wrong?


While I happen to use a https proxy, I'm confident this isn't the problem. I've configured the environment variable https_proxy (per the npm user guide). I know the environment variable is correct, because the Python package manager pip follows it correctly.

I believe the problem relates to SSL certificates, because if I download that URL with wget, I get an explicit error about certificates

$ wget https://registry.npmjs.org/coffee-script
SYSTEM_WGETRC = c:/progra~1/wget/etc/wgetrc
syswgetrc = c:/progra~1/wget/etc/wgetrc
--2012-12-17 12:14:07--  https://registry.npmjs.org/coffee-script
Resolving corpproxy... 10.254.215.35
Connecting to corpproxy|10.254.215.35|:8080... connected.
ERROR: cannot verify registry.npmjs.org's certificate, issued by `/C=US/ST=CA/L=Oakland/O=npm/OU=npm Certificate Authority/CN=npmCA/[email protected]':
  Unable to locally verify the issuer's authority.
To connect to registry.npmjs.org insecurely, use `--no-check-certificate'.
Unable to establish SSL connection.

How can I fix this? Without compromising security.


I used to get SSL certificate errors in my web browser too, until I installed the 'npmCA' certificate as a 'trusted root certification authority' in Control Panel's Internet Options (screenshot enter image description here )


Edit: I tried an insecure workaround per https://npmjs.org/doc/config.html#strict-ssl

npm set strict-ssl false

Yet it still times out with the same error

$ npm install coffee-script
npm http GET https://registry.npmjs.org/coffee-script
npm http GET https://registry.npmjs.org/coffee-script
npm http GET https://registry.npmjs.org/coffee-script
npm ERR! Error: tunneling socket could not be established, sutatusCode=403
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

TL;DR - Just run this and don't disable your security:

Replace existing certs

# Windows/MacOS/Linux 
npm config set cafile "<path to your certificate file>"

# Check the 'cafile'
npm config get cafile

or extend existing certs

Set this environment variable to extend pre-defined certs: NODE_EXTRA_CA_CERTS to "<path to certificate file>"

Full story

I've had to work with npm, pip, maven etc. behind a corporate firewall under Windows - it's not fun. I'll try and keep this platform agnostic/aware where possible.

HTTP_PROXY & HTTPS_PROXY

HTTP_PROXY & HTTPS_PROXY are environment variables used by lots of software to know where your proxy is. Under Windows, lots of software also uses your OS specified proxy which is a totally different thing. That means you can have Chrome (which uses the proxy specified in your Internet Options) connecting to the URL just fine, but npm, pip, maven etc. not working because they use HTTPS_PROXY (except when they use HTTP_PROXY - see later). Normally the environment variable would look something like:

http://proxy.example.com:3128

But you're getting a 403 which suggests you're not being authenticated against your proxy. If it is basic authentication on the proxy, you'll want to set the environment variable to something of the form:

http://user:[email protected]:3128

The dreaded NTLM

There is an HTTP status code 407 (proxy authentication required), which is the more correct way of saying it's the proxy rather than the destination server that's rejecting your request. That code plagued me for the longest time until after a lot of time on Google, I learned my proxy used NTLM authentication. HTTP basic authentication wasn't enough to satisfy whatever proxy my corporate overlords had installed. I resorted to using Cntlm on my local machine (unauthenticated), then had it handle the NTLM authentication with the upstream proxy. Then I had to tell all the programs that couldn't do NTLM to use my local machine as the proxy - which is generally as simple as setting HTTP_PROXY and HTTPS_PROXY. Otherwise, for npm use (as @Agus suggests):

npm config set proxy http://proxy.example.com:3128
npm config set https-proxy http://proxy.example.com:3128

"We need to decrypt all HTTPS traffic because viruses"

After this set-up had been humming along (clunkily) for about a year, the corporate overlords decided to change the proxy. Not only that, but it would no longer use NTLM! A brave new world to be sure. But because those writers of malicious software were now delivering malware via HTTPS, the only way they could protect we poor innocent users was to man-in-the-middle every connection to scan for threats before they even reached us. As you can imagine, I was overcome with the feeling of safety.

To cut a long story short, the self-signed certificate needs to be installed into npm to avoid SELF_SIGNED_CERT_IN_CHAIN:

npm config set cafile "<path to certificate file>"

Alternatively, the NODE_EXTRA_CA_CERTS environment variable can be set to the certificate file.

I think that's everything I know about getting npm to work behind a proxy/firewall. May someone find it useful.

Edit: It's a really common suggestion to turn off HTTPS for this problem either by using an HTTP registry or setting NODE_TLS_REJECT_UNAUTHORIZED. These are not good ideas because you're opening yourself up to further man-in-the-middle or redirection attacks. A quick spoof of your DNS records on the machine doing the package installation and you'll find yourself trusting packages from anywhere. It may seem like a lot of work to make HTTPS work, but it is highly recommended. When you're the one responsible for allowing untrusted code into the company, you'll understand why.

Edit 2: Keep in mind that setting npm config set cafile <path> causes npm to only use the certs provided in that file, instead of extending the existing ones with it.

If you want to extend the existing certs (e.g. with a company cert) using the environment variable NODE_EXTRA_CA_CERTS to link to the file is the way to go and can save you a lot of hassle. See how-to-add-custom-certificate-authority-ca-to-nodejs


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...