Skip to content

Commit 165b5c6

Browse files
committed
require verify-ca to specify sslrootcert when sslmode is libpq compat
1 parent f16737e commit 165b5c6

File tree

3 files changed

+48
-26
lines changed

3 files changed

+48
-26
lines changed

packages/pg-connection-string/README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,18 +88,21 @@ Query parameters follow a `?` character, including the following special query p
8888
* `encoding=<encoding>` - sets the `client_encoding` property
8989
* `ssl=1`, `ssl=true`, `ssl=0`, `ssl=false` - sets `ssl` to true or false, accordingly
9090
* `sslcompat=libpq` - use libpq semantics for `sslmode`
91+
* `sslmode=<sslmode>` when `sslcompat` is not set
92+
* `sslmode=disable` - sets `ssl` to false
93+
* `sslmode=no-verify` - sets `ssl` to `{ rejectUnauthorized: false }`
94+
* `sslmode=prefer`, `sslmode=require`, `sslmode=verify-ca`, `sslmode=verify-full` - sets `ssl` to true
9195
* `sslmode=<sslmode>` when `sslcompat=libpq`
9296
* `sslmode=disable` - sets `ssl` to false
9397
* `sslmode=prefer` - sets `ssl` to `{ rejectUnauthorized: false }`
9498
* `sslmode=require` - sets `ssl` to `{ rejectUnauthorized: false }` unless `sslrootcert` is specified, in which case it behaves like `verify-ca`
9599
* `sslmode=verify-ca` - sets `ssl` to `{ checkServerIdentity: no-op }` (verify CA, but not server identity). This verifies the presented certificate against the effective CA, i.e. the one specified in sslrootcert or the system CA if sslrootcert was not specified.
96100
* `sslmode=verify-full` - sets `ssl` to `{}` (verify CA and server identity)
97-
* `sslmode=<sslmode>` when `sslcompat` is not set
98-
* `sslmode=disable` - sets `ssl` to false
99-
* `sslmode=no-verify` - sets `ssl` to `{ rejectUnauthorized: false }`
100-
* `sslmode=prefer`, `sslmode=require`, `sslmode=verify-ca`, `sslmode=verify-full` - sets `ssl` to true
101101
* `sslcert=<filename>` - reads data from the given file and includes the result as `ssl.cert`
102102
* `sslkey=<filename>` - reads data from the given file and includes the result as `ssl.key`
103103
* `sslrootcert=<filename>` - reads data from the given file and includes the result as `ssl.ca`
104104

105105
A bare relative URL, such as `salesdata`, will indicate a database name while leaving other properties empty.
106+
107+
> [!CAUTION]
108+
> Choosing an sslmode other than verify-full has serious security implications. Please read https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-SSLMODE-STATEMENTS to understand the trade-offs.

packages/pg-connection-string/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ function parse(str) {
107107
break
108108
}
109109
case 'verify-ca': {
110+
if (!config.ssl.ca) {
111+
throw new Error(
112+
'SECURITY WARNING: Using sslmode=verify-ca requires specifying a CA with sslrootcert. If a public CA is used, verify-ca allows connections to a server that somebody else may have registered with the CA, making you vulnerable to Man-in-the-Middle attacks. Either specify a custom CA certificate with sslrootcert parameter or use sslmode=verify-full for proper security.'
113+
)
114+
}
110115
config.ssl.checkServerIdentity = function () {}
111116
break
112117
}

packages/pg-connection-string/test/parse.js

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -256,27 +256,42 @@ describe('parse', function () {
256256
subject.ssl.should.eql(false)
257257
})
258258

259-
it('configuration parameter sslmode=prefer with libpq compatibility', function () {
260-
var connectionString = 'pg:///?sslmode=prefer&sslcompat=libpq'
259+
it('configuration parameter sslmode=prefer', function () {
260+
var connectionString = 'pg:///?sslmode=prefer'
261261
var subject = parse(connectionString)
262-
subject.ssl.should.eql({
263-
rejectUnauthorized: false,
264-
})
262+
subject.ssl.should.eql({})
265263
})
266264

267-
it('configuration parameter sslmode=require with libpq compatibility', function () {
268-
var connectionString = 'pg:///?sslmode=require&sslcompat=libpq'
265+
it('configuration parameter sslmode=require', function () {
266+
var connectionString = 'pg:///?sslmode=require'
267+
var subject = parse(connectionString)
268+
subject.ssl.should.eql({})
269+
})
270+
271+
it('configuration parameter sslmode=verify-ca', function () {
272+
var connectionString = 'pg:///?sslmode=verify-ca'
273+
var subject = parse(connectionString)
274+
subject.ssl.should.eql({})
275+
})
276+
277+
it('configuration parameter sslmode=verify-full', function () {
278+
var connectionString = 'pg:///?sslmode=verify-full'
279+
var subject = parse(connectionString)
280+
subject.ssl.should.eql({})
281+
})
282+
283+
it('configuration parameter ssl=true and sslmode=require still work with sslrootcert=/path/to/ca', function () {
284+
var connectionString = 'pg:///?ssl=true&sslrootcert=' + __dirname + '/example.ca&sslmode=require'
269285
var subject = parse(connectionString)
270286
subject.ssl.should.eql({
271-
rejectUnauthorized: false,
287+
ca: 'example ca\n',
272288
})
273289
})
274290

275-
it('configuration parameter sslmode=verify-ca with libpq compatibility', function () {
276-
var connectionString = 'pg:///?sslmode=verify-ca&sslcompat=libpq'
291+
it('configuration parameter sslmode=disable with libpq compatibility', function () {
292+
var connectionString = 'pg:///?sslmode=disable&sslcompat=libpq'
277293
var subject = parse(connectionString)
278-
subject.ssl.should.have.property('checkServerIdentity').that.is.a('function')
279-
expect(subject.ssl.checkServerIdentity()).to.be.undefined
294+
subject.ssl.should.eql(false)
280295
})
281296

282297
it('configuration parameter sslmode=prefer with libpq compatibility', function () {
@@ -297,25 +312,24 @@ describe('parse', function () {
297312

298313
it('configuration parameter sslmode=verify-ca with libpq compatibility', function () {
299314
var connectionString = 'pg:///?sslmode=verify-ca&sslcompat=libpq'
315+
expect(function () {
316+
parse(connectionString)
317+
}).to.throw()
318+
})
319+
320+
it('configuration parameter sslmode=verify-ca and sslrootcert with libpq compatibility', function () {
321+
var connectionString = 'pg:///?sslmode=verify-ca&sslcompat=libpq&sslrootcert=' + __dirname + '/example.ca'
300322
var subject = parse(connectionString)
301323
subject.ssl.should.have.property('checkServerIdentity').that.is.a('function')
302324
expect(subject.ssl.checkServerIdentity()).be.undefined
303325
})
304326

305-
it('configuration parameter sslmode=verify-full', function () {
306-
var connectionString = 'pg:///?sslmode=verify-full'
327+
it('configuration parameter sslmode=verify-full with libpq compatibility', function () {
328+
var connectionString = 'pg:///?sslmode=verify-full&sslcompat=libpq'
307329
var subject = parse(connectionString)
308330
subject.ssl.should.eql({})
309331
})
310332

311-
it('configuration parameter ssl=true and sslmode=require still work with sslrootcert=/path/to/ca', function () {
312-
var connectionString = 'pg:///?ssl=true&sslrootcert=' + __dirname + '/example.ca&sslmode=require'
313-
var subject = parse(connectionString)
314-
subject.ssl.should.eql({
315-
ca: 'example ca\n',
316-
})
317-
})
318-
319333
it('configuration parameter ssl=true and sslmode=require still work with sslrootcert=/path/to/ca with libpq compatibility', function () {
320334
var connectionString = 'pg:///?ssl=true&sslrootcert=' + __dirname + '/example.ca&sslmode=require&sslcompat=libpq'
321335
var subject = parse(connectionString)

0 commit comments

Comments
 (0)