Skip to content

Commit 31eaa05

Browse files
brianccharmander
andcommitted
Remove password from stringified outputs (#2066)
* Remove password from stringified outputs Theres a security concern where if you're not careful and you include your client or pool instance in console.log or stack traces it might include the database password. To widen the pit of success I'm making that field non-enumerable. You can still get at it...it just wont show up "by accident" when you're logging things now. The backwards compatiblity impact of this is very small, but it is still technically somewhat an API change so...8.0. * Implement feedback * Fix more whitespace the autoformatter changed * Simplify code a bit * Remove password from stringified outputs (#2070) * Keep ConnectionParameters’s password property writable `Client` writes to it when `password` is a function. * Avoid creating password property on pool options when it didn’t exist previously. * Allow password option to be non-enumerable to avoid breaking uses like `new Pool(existingPool.options)`. * Make password property definitions consistent in formatting and configurability. Co-authored-by: Charmander <[email protected]>
1 parent c909aa6 commit 31eaa05

File tree

6 files changed

+74
-3
lines changed

6 files changed

+74
-3
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ package-lock.json
77
*.swp
88
dist
99
.DS_Store
10+
.vscode/

packages/pg-pool/index.js

+12
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,18 @@ class Pool extends EventEmitter {
6060
constructor (options, Client) {
6161
super()
6262
this.options = Object.assign({}, options)
63+
64+
if (options != null && 'password' in options) {
65+
// "hiding" the password so it doesn't show up in stack traces
66+
// or if the client is console.logged
67+
Object.defineProperty(this.options, 'password', {
68+
configurable: true,
69+
enumerable: false,
70+
writable: true,
71+
value: options.password
72+
})
73+
}
74+
6375
this.options.max = this.options.max || this.options.poolSize || 10
6476
this.log = this.options.log || function () { }
6577
this.Client = this.options.Client || Client || require('pg').Client

packages/pg/lib/client.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,16 @@ var Client = function (config) {
3030
this.database = this.connectionParameters.database
3131
this.port = this.connectionParameters.port
3232
this.host = this.connectionParameters.host
33-
this.password = this.connectionParameters.password
33+
34+
// "hiding" the password so it doesn't show up in stack traces
35+
// or if the client is console.logged
36+
Object.defineProperty(this, 'password', {
37+
configurable: true,
38+
enumerable: false,
39+
writable: true,
40+
value: this.connectionParameters.password
41+
})
42+
3443
this.replication = this.connectionParameters.replication
3544

3645
var c = config || {}

packages/pg/lib/connection-parameters.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,16 @@ var ConnectionParameters = function (config) {
5454
this.database = val('database', config)
5555
this.port = parseInt(val('port', config), 10)
5656
this.host = val('host', config)
57-
this.password = val('password', config)
57+
58+
// "hiding" the password so it doesn't show up in stack traces
59+
// or if the client is console.logged
60+
Object.defineProperty(this, 'password', {
61+
configurable: true,
62+
enumerable: false,
63+
writable: true,
64+
value: val('password', config)
65+
})
66+
5867
this.binary = val('binary', config)
5968
this.ssl = typeof config.ssl === 'undefined' ? useSsl() : config.ssl
6069
this.client_encoding = val('client_encoding', config)

packages/pg/lib/native/client.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,15 @@ var Client = module.exports = function (config) {
4343
// for the time being. TODO: deprecate all this jazz
4444
var cp = this.connectionParameters = new ConnectionParameters(config)
4545
this.user = cp.user
46-
this.password = cp.password
46+
47+
// "hiding" the password so it doesn't show up in stack traces
48+
// or if the client is console.logged
49+
const hiddenPassword = cp.password
50+
Object.defineProperty(this, 'password', {
51+
enumerable: false,
52+
writable: true,
53+
value: hiddenPassword
54+
})
4755
this.database = cp.database
4856
this.host = cp.host
4957
this.port = cp.port
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
"use strict"
3+
const helper = require('./../test-helper')
4+
const assert = require('assert')
5+
const util = require('util')
6+
7+
const suite = new helper.Suite()
8+
9+
const password = 'FAIL THIS TEST'
10+
11+
suite.test('Password should not exist in toString() output', () => {
12+
const pool = new helper.pg.Pool({ password })
13+
const client = new helper.pg.Client({ password })
14+
assert(pool.toString().indexOf(password) === -1);
15+
assert(client.toString().indexOf(password) === -1);
16+
})
17+
18+
suite.test('Password should not exist in util.inspect output', () => {
19+
const pool = new helper.pg.Pool({ password })
20+
const client = new helper.pg.Client({ password })
21+
const depth = 20;
22+
assert(util.inspect(pool, { depth }).indexOf(password) === -1);
23+
assert(util.inspect(client, { depth }).indexOf(password) === -1);
24+
})
25+
26+
suite.test('Password should not exist in json.stringfy output', () => {
27+
const pool = new helper.pg.Pool({ password })
28+
const client = new helper.pg.Client({ password })
29+
const depth = 20;
30+
assert(JSON.stringify(pool).indexOf(password) === -1);
31+
assert(JSON.stringify(client).indexOf(password) === -1);
32+
})

0 commit comments

Comments
 (0)