npm / cli

the package manager for JavaScript
https://docs.npmjs.com/cli/
Other
8.36k stars 3.09k forks source link

[BUG]NPM not respecting node environment variables --tls-min-v1.2 #3002

Closed JohanSpannare closed 3 years ago

JohanSpannare commented 3 years ago

Possibility to force min and max TLS version to use by npm vis proxy.

npm is by default (see wireshark) trying to use TLSv1 witch is not supported by our proxy. Have tried to find a way to configure node/npm to honor

--tls-min-v1.2 and or --tls-cipher-list=list

without success.

Wireshark dump (NOT WORKING)

image

Wireshark dump (WORKING)

image

Conclusion

When using proxy, TLSv1.2 is not used in the protocol version, so it seams to me that the proxy used is the problem.

RFC 5246

RFC States that protocol version should match the version of TLS used.

Since there are various versions of TLS (1.0, 1.1, 1.2, and any future versions) and SSL (2.0 and 3.0), means are needed to negotiate the specific protocol version to use. The TLS protocol provides a built-in mechanism for version negotiation so as not to bother other protocol components with the complexities of version selection.

https://tools.ietf.org/html/rfc5246#section-7.4

Logs

The first example below show the request without any configurations (TLSv1), the second request has min and max version set, it still uses protocol TLSv1, but annonce 1.2 in supported protocols.

npm timing idealTree:userRequests Completed in 1ms
  https-proxy-agent:agent creating new HttpsProxyAgent instance: { host: 'localhost', port: '8888', protocol: 'http:', path: '/', auth: 'yoda:1617254371_54ed16681a4daa4ca62ff2533fc2e962_89ef64a19117cbbfaaf8c0baa0188a1e8', ca: null, cert: null, key: null, timeout: 300001, localAddress: undefined, maxSockets: 12, rejectUnauthorized: false } +0ms
  agent-base Resolving socket for 'https:' request: 'GET /artifactory/api/npm/seb-npm/sax' +0ms
  https-proxy-agent:agent Creating `net.Socket`: { host: 'localhost', port: 8888, protocol: 'http:', auth: 'yoda:1617254371_54ed16681a4daa4ca62ff2533fc2e962_89ef64a19117cbbfaaf8c0baa0188a1e8', ca: null, cert: null, key: null, timeout: 300001, localAddress: undefined, maxSockets: 12, rejectUnauthorized: false } +4ms
  https-proxy-agent:parse-proxy-response got proxy server response: 'HTTP/1.0 200 OK' +0ms
  https-proxy-agent:agent Upgrading socket connection to TLS +47ms
  https-proxy-agent:parse-proxy-response onclose had error false  #+3ms
npm timing idealTree:userRequests Completed in 1ms
Sent Record........] | idealTree:npmtemp: sill idealTree buildDeps
Header:
  Version = TLS 1.0 (0x301)
  Content Type = Handshake (22)
  Length = 363
    ClientHello, Length=359
      client_version=0x303 (TLS 1.2)
      Random:
        gmt_unix_time=0x05C5549C
        random_bytes (len=28): 833397A54D1BD6CCA8B843C7EDCB58378D0943BD7773D3EAD79FF133
      session_id (len=32): 4125AD6F5F44BACEDF0D19B923691B14BA5E6DC2318F22E0A4A13F56D5D6DBE1
      cipher_suites (len=118)
        {0x13, 0x02} TLS_AES_256_GCM_SHA384
        {0x13, 0x03} TLS_CHACHA20_POLY1305_SHA256
        {0x13, 0x01} TLS_AES_128_GCM_SHA256
        {0xC0, 0x2F} TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        {0xC0, 0x2B} TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
        {0xC0, 0x30} TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        {0xC0, 0x2C} TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        {0x00, 0x9E} TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
        {0xC0, 0x27} TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
        {0x00, 0x67} TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
        {0xC0, 0x28} TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
        {0x00, 0x6B} TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
        {0x00, 0xA3} TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
        {0x00, 0x9F} TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
        {0xCC, 0xA9} TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
        {0xCC, 0xA8} TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
        {0xCC, 0xAA} TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
        {0xC0, 0xAF} TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
        {0xC0, 0xAD} TLS_ECDHE_ECDSA_WITH_AES_256_CCM
        {0xC0, 0xA3} TLS_DHE_RSA_WITH_AES_256_CCM_8
        {0xC0, 0x9F} TLS_DHE_RSA_WITH_AES_256_CCM
        {0xC0, 0x5D} TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384
        {0xC0, 0x61} TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384
        {0xC0, 0x57} TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384
        {0xC0, 0x53} TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384
        {0x00, 0xA2} TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
        {0xC0, 0xAE} TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
        {0xC0, 0xAC} TLS_ECDHE_ECDSA_WITH_AES_128_CCM
        {0xC0, 0xA2} TLS_DHE_RSA_WITH_AES_128_CCM_8
        {0xC0, 0x9E} TLS_DHE_RSA_WITH_AES_128_CCM
        {0xC0, 0x5C} TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256
        {0xC0, 0x60} TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256
        {0xC0, 0x56} TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256
        {0xC0, 0x52} TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256
        {0xC0, 0x24} TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
        {0x00, 0x6A} TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
        {0xC0, 0x23} TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
        {0x00, 0x40} TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
        {0xC0, 0x0A} TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
        {0xC0, 0x14} TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
        {0x00, 0x39} TLS_DHE_RSA_WITH_AES_256_CBC_SHA
        {0x00, 0x38} TLS_DHE_DSS_WITH_AES_256_CBC_SHA
        {0xC0, 0x09} TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
        {0xC0, 0x13} TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
        {0x00, 0x33} TLS_DHE_RSA_WITH_AES_128_CBC_SHA
        {0x00, 0x32} TLS_DHE_DSS_WITH_AES_128_CBC_SHA
        {0x00, 0x9D} TLS_RSA_WITH_AES_256_GCM_SHA384
        {0xC0, 0xA1} TLS_RSA_WITH_AES_256_CCM_8
        {0xC0, 0x9D} TLS_RSA_WITH_AES_256_CCM
        {0xC0, 0x51} TLS_RSA_WITH_ARIA_256_GCM_SHA384
        {0x00, 0x9C} TLS_RSA_WITH_AES_128_GCM_SHA256
        {0xC0, 0xA0} TLS_RSA_WITH_AES_128_CCM_8
        {0xC0, 0x9C} TLS_RSA_WITH_AES_128_CCM
        {0xC0, 0x50} TLS_RSA_WITH_ARIA_128_GCM_SHA256
        {0x00, 0x3D} TLS_RSA_WITH_AES_256_CBC_SHA256
        {0x00, 0x3C} TLS_RSA_WITH_AES_128_CBC_SHA256
        {0x00, 0x35} TLS_RSA_WITH_AES_256_CBC_SHA
        {0x00, 0x2F} TLS_RSA_WITH_AES_128_CBC_SHA
        {0x00, 0xFF} TLS_EMPTY_RENEGOTIATION_INFO_SCSV
      compression_methods (len=1)
        No Compression (0x00)
      extensions, length = 168
        extension_type=server_name(0), length=19
          0000 - 00 11 00 00 0e 72 65 70-6f 2e 73 65 62 61 6e   .....repo.seban
          000f - 6b 2e 73 65                                    k.se
        extension_type=ec_point_formats(11), length=4
          uncompressed (0)
          ansiX962_compressed_prime (1)
          ansiX962_compressed_char2 (2)
        extension_type=supported_groups(10), length=12
          ecdh_x25519 (29)
          secp256r1 (P-256) (23)
          ecdh_x448 (30)
          secp521r1 (P-521) (25)
          secp384r1 (P-384) (24)
        extension_type=session_ticket(35), length=0
        extension_type=encrypt_then_mac(22), length=0
        extension_type=extended_master_secret(23), length=0
        extension_type=signature_algorithms(13), length=48
          ecdsa_secp256r1_sha256 (0x0403)
          ecdsa_secp384r1_sha384 (0x0503)
          ecdsa_secp521r1_sha512 (0x0603)
          ed25519 (0x0807)
          ed448 (0x0808)
          rsa_pss_pss_sha256 (0x0809)
          rsa_pss_pss_sha384 (0x080a)
          rsa_pss_pss_sha512 (0x080b)
          rsa_pss_rsae_sha256 (0x0804)
          rsa_pss_rsae_sha384 (0x0805)
          rsa_pss_rsae_sha512 (0x0806)
          rsa_pkcs1_sha256 (0x0401)
          rsa_pkcs1_sha384 (0x0501)
          rsa_pkcs1_sha512 (0x0601)
          ecdsa_sha224 (0x0303)
          ecdsa_sha1 (0x0203)
          rsa_pkcs1_sha224 (0x0301)
          rsa_pkcs1_sha1 (0x0201)
          dsa_sha224 (0x0302)
          dsa_sha1 (0x0202)
          dsa_sha256 (0x0402)
          dsa_sha384 (0x0502)
          dsa_sha512 (0x0602)
        extension_type=supported_versions(43), length=5
          TLS 1.3 (772)
          TLS 1.2 (771)
        extension_type=psk_key_exchange_modes(45), length=2
          psk_dhe_ke (1)
        extension_type=key_share(51), length=38
            NamedGroup: ecdh_x25519 (29)
            key_exchange:  (len=32): 7A772754AC728AE2E7194FEFBB5EAA6AF8536C776E08FDAC0D0715A2A883106D

TLS Options used to force TLSv1.2

    options.minVersion = 'TLSv1.2'
    options.maxVersion = 'TLSv1.2'
https-proxy-agent:agent Upgrading socket connection to TLS +42ms
Header:
  Version = TLS 1.0 (0x301)
  Content Type = Handshake (22)
  Length = 268
    ClientHello, Length=264
      client_version=0x303 (TLS 1.2)
      Random:
        gmt_unix_time=0x6F963E3C
        random_bytes (len=28): 97135C742E784711B23AF1230A4B4A8852F8DEEBE27B06F1E70278FE
      session_id (len=0):
      cipher_suites (len=112)
        {0xC0, 0x2F} TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        {0xC0, 0x2B} TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
        {0xC0, 0x30} TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        {0xC0, 0x2C} TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        {0x00, 0x9E} TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
        {0xC0, 0x27} TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
        {0x00, 0x67} TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
        {0xC0, 0x28} TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
        {0x00, 0x6B} TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
        {0x00, 0xA3} TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
        {0x00, 0x9F} TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
        {0xCC, 0xA9} TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
        {0xCC, 0xA8} TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
        {0xCC, 0xAA} TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
        {0xC0, 0xAF} TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
        {0xC0, 0xAD} TLS_ECDHE_ECDSA_WITH_AES_256_CCM
        {0xC0, 0xA3} TLS_DHE_RSA_WITH_AES_256_CCM_8
        {0xC0, 0x9F} TLS_DHE_RSA_WITH_AES_256_CCM
        {0xC0, 0x5D} TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384
        {0xC0, 0x61} TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384
        {0xC0, 0x57} TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384
        {0xC0, 0x53} TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384
        {0x00, 0xA2} TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
        {0xC0, 0xAE} TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
        {0xC0, 0xAC} TLS_ECDHE_ECDSA_WITH_AES_128_CCM
        {0xC0, 0xA2} TLS_DHE_RSA_WITH_AES_128_CCM_8
        {0xC0, 0x9E} TLS_DHE_RSA_WITH_AES_128_CCM
        {0xC0, 0x5C} TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256
        {0xC0, 0x60} TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256
        {0xC0, 0x56} TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256
        {0xC0, 0x52} TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256
        {0xC0, 0x24} TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
        {0x00, 0x6A} TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
        {0xC0, 0x23} TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
        {0x00, 0x40} TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
        {0xC0, 0x0A} TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
        {0xC0, 0x14} TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
        {0x00, 0x39} TLS_DHE_RSA_WITH_AES_256_CBC_SHA
        {0x00, 0x38} TLS_DHE_DSS_WITH_AES_256_CBC_SHA
        {0xC0, 0x09} TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
        {0xC0, 0x13} TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
        {0x00, 0x33} TLS_DHE_RSA_WITH_AES_128_CBC_SHA
        {0x00, 0x32} TLS_DHE_DSS_WITH_AES_128_CBC_SHA
        {0x00, 0x9D} TLS_RSA_WITH_AES_256_GCM_SHA384
        {0xC0, 0xA1} TLS_RSA_WITH_AES_256_CCM_8
        {0xC0, 0x9D} TLS_RSA_WITH_AES_256_CCM
        {0xC0, 0x51} TLS_RSA_WITH_ARIA_256_GCM_SHA384
        {0x00, 0x9C} TLS_RSA_WITH_AES_128_GCM_SHA256
        {0xC0, 0xA0} TLS_RSA_WITH_AES_128_CCM_8
        {0xC0, 0x9C} TLS_RSA_WITH_AES_128_CCM
        {0xC0, 0x50} TLS_RSA_WITH_ARIA_128_GCM_SHA256
        {0x00, 0x3D} TLS_RSA_WITH_AES_256_CBC_SHA256
        {0x00, 0x3C} TLS_RSA_WITH_AES_128_CBC_SHA256
        {0x00, 0x35} TLS_RSA_WITH_AES_256_CBC_SHA
        {0x00, 0x2F} TLS_RSA_WITH_AES_128_CBC_SHA
        {0x00, 0xFF} TLS_EMPTY_RENEGOTIATION_INFO_SCSV
      compression_methods (len=1)
        No Compression (0x00)
      extensions, length = 111
        extension_type=server_name(0), length=19
          0000 - 00 11 00 00 0e 72 65 70-6f 2e 73 65 62 61 6e   .....repo.seban
          000f - 6b 2e 73 65                                    k.se
        extension_type=ec_point_formats(11), length=4
          uncompressed (0)
          ansiX962_compressed_prime (1)
          ansiX962_compressed_char2 (2)
        extension_type=supported_groups(10), length=12
          ecdh_x25519 (29)
          secp256r1 (P-256) (23)
          ecdh_x448 (30)
          secp521r1 (P-521) (25)
          secp384r1 (P-384) (24)
        extension_type=session_ticket(35), length=0
        extension_type=encrypt_then_mac(22), length=0
        extension_type=extended_master_secret(23), length=0
        extension_type=signature_algorithms(13), length=48
          ecdsa_secp256r1_sha256 (0x0403)
          ecdsa_secp384r1_sha384 (0x0503)
          ecdsa_secp521r1_sha512 (0x0603)
          ed25519 (0x0807)
          ed448 (0x0808)
          rsa_pss_pss_sha256 (0x0809)
          rsa_pss_pss_sha384 (0x080a)
          rsa_pss_pss_sha512 (0x080b)
          rsa_pss_rsae_sha256 (0x0804)
          rsa_pss_rsae_sha384 (0x0805)
          rsa_pss_rsae_sha512 (0x0806)
          rsa_pkcs1_sha256 (0x0401)
          rsa_pkcs1_sha384 (0x0501)
          rsa_pkcs1_sha512 (0x0601)
          ecdsa_sha224 (0x0303)
          ecdsa_sha1 (0x0203)
          rsa_pkcs1_sha224 (0x0301)
          rsa_pkcs1_sha1 (0x0201)
          dsa_sha224 (0x0302)
          dsa_sha1 (0x0202)
          dsa_sha256 (0x0402)
          dsa_sha384 (0x0502)
          dsa_sha512 (0x0602)

  https-proxy-agent:parse-proxy-response onclose had error false +36ms

Workaround

Remove "headers.Connection = 'close';" at line 111 in "C:\Program Files\nodejs\node_modules\npm\node_modules\https-proxy-agent\dist\agent.js" seams to "work around" the problem.

TooTallNate/node-https-proxy-agent#18

This PR will solve this issue TooTallNate/node-https-proxy-agent/pull/112

JohanSpannare commented 3 years ago

@isaacs please have a look at this issue

nlf commented 3 years ago

what you're providing isn't environment variables, they're command line flags. we definitely do not pass unknown command line flags through to node proper, so you're right that doesn't work and deliberately will not.

as for your root concern of being able to specify a minimum tls version, that could potentially be implemented as a new feature but if there's an incompatibility in the proxy agent we leverage then it likely won't be done until a fix lands upstream.

JohanSpannare commented 3 years ago

what you're providing isn't environment variables, they're command line flags. we definitely do not pass unknown command line flags through to node proper, so you're right that doesn't work and deliberately will not.

as for your root concern of being able to specify a minimum tls version, that could potentially be implemented as a new feature but if there's an incompatibility in the proxy agent we leverage then it likely won't be done until a fix lands upstream.

Yes, they are arguments, but you can also set them by editing js files.

First problem

The problem are still there, TLS Client Hello message from https-proxy-agent is not following the RFC standard. It sends protocol version 1.0, but at the same time uses client version 1.2. This is not valid and will be dropped by WAF (Web Application Firewall/ F5).

Second problem

And the HTTP connection header is set to close, but what will cause the TLS negotiation to fail since F5 will close the connection (RFC standard) when the Client Hello message is not supported (We only support version >1.2 in TLS).

Conclusion

NPM CLI is saidly not supporting TLS >1.0 over HTTPS Proxy when its using HTTPS-PROXY-AGENT as its module for proxy´s. Either HTTPS-PROXY-AGENT need to be patched, or NPM CLI need to take use of some other module for it´s proxy support.

darcyclarke commented 3 years ago

npm `v6` is no longer in active development; We will continue to push security releases to `v6` at our team's discretion as-per our Support Policy.

If your bug is reproducible on `v7`, please re-file this issue using our new issue template.

If your issue was a feature request, please consider opening a new RRFC or RFC. If your issue was a question or other idea that was not CLI-specific, consider opening a discussion on our feedback repo

Closing: This is an automated message.