node-postgres icon indicating copy to clipboard operation
node-postgres copied to clipboard

IP hosts are not validated correctly against certificate altnames

Open RazerM opened this issue 5 years ago • 5 comments

For example, connecting to IP 1.2.3.4 yields the following error:

Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: Host: localhost. is not in the cert's altnames: IP Address:1.2.3.4
       at Object.checkServerIdentity (tls.js:250:17)
       at TLSSocket.onConnectSecure (_tls_wrap.js:1098:27)
       at TLSSocket.emit (events.js:198:13)
       at TLSSocket._finishInit (_tls_wrap.js:666:8)

Since TLS support was added to pg, it has passed a socket to tls.connect, meaning the host should be passed separately (it isn't). It passed servername, which is not valid for IP addresses and was removed in #1890.

The reason that the error message above uses localhost can be found in _tls_wrap.js.

I found a previous issue (#2178) about this but it wasn't fixed. The correct fix is to always pass host. The documentation for options.socket says:

If this option is specified, path, host and port are ignored, except for certificate validation.

I can submit a PR but I will need help if you'd like a test for this.

RazerM avatar Jul 02 '20 14:07 RazerM

Related to https://github.com/brianc/node-postgres-docs/issues/79

hjr3 avatar Jul 16 '20 02:07 hjr3

We encountered the same issue when using sequelize to connect to PG database. It's blocking us from moving forward with changing DB connection architecture.

@RazerM @charmander Do you know when it will be closed and if it will be released soon? Do you need any help to finalize it?

qooban avatar Nov 13 '20 05:11 qooban

The TLS issue can be demonstrated with https://1.1.1.1:

const net = require('net');
const tls = require('tls');

function connect(port, host) {
  const stream = new net.Socket();
  stream.connect(port, host);

  const options = {
    socket: stream,
    // host,
  };

  tls.connect(options);
}

connect(443, '1.1.1.1');
Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: Host: localhost. is not in the cert's altnames: DNS:cloudflare-dns.com, DNS:*.cloudflare-dns.com, DNS:one.one.one.one, IP Address:1.1.1.1, IP Address:1.0.0.1, IP Address:162.159.36.1, IP Address:162.159.46.1, IP Address:2606:4700:4700:0:0:0:0:1111, IP Address:2606:4700:4700:0:0:0:0:1001, IP Address:2606:4700:4700:0:0:0:0:64, IP Address:2606:4700:4700:0:0:0:0:6400

Uncommenting the host variable fixes it.

RazerM avatar May 03 '21 10:05 RazerM

Was pulling my hair out about this issue. Am putting a solution here since search engines seem to find it.

Not sure if this is the 100% best fix (but much better than rejectUnauthorized=false).

My Error: 'Hostname/IP does not match certificate's altnames: Host: localhost. is not in the cert's altnames: DNS:[address]a.us-central1.sql.goog'

Fix:

    7          ssl: {
    8           rejectUnauthorized: process.env.RUNTIME_ENV === "production", <- Keep security in prod!
    9           ca: process.env.POSTGRES_RO_SERVER_CA,   <- ca cert string
   10           key: process.env.POSTGRES_RO_CLIENT_KEY,  <- client key string
   11           cert: process.env.POSTGRES_RO_CLIENT_CERT, <- client cert string
   12           servername: process.env.POSTGRES_RO_SERVER_NAME,    <- DNS string value for db.
   13         },

Adding the expected DNS value in the error (I thought it would be in the cert too but I can't see it with openssl) as the servername makes the certs not try to verify against localhost.

paul-greco2 avatar Aug 01 '24 15:08 paul-greco2

servername did the trick

gsouf avatar Feb 22 '25 18:02 gsouf