Skip to content

Commit 0dc8f73

Browse files
authored
MONGOSH-294 - Database credentials not redacted from session logs or command history (#288)
* Database credentials not redacted from session logs or command history * redact connect event * redact for runCommand
1 parent 5e5276a commit 0dc8f73

File tree

11 files changed

+91
-47
lines changed

11 files changed

+91
-47
lines changed

packages/history/src/history.spec.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ describe('changeHistory', () => {
1919
it('removes URI having Mongo from history', () => {
2020
const i = ['m = new Mongo(\'mongodb://anna:[email protected]:27017/test\')', 'db.shipwrecks.findOne()', 'use ships'];
2121
changeHistory(i);
22-
expect(i).to.deep.equal(['m = new Mongo(\'mongodb://<credentials>@127.0.0.1:27017/test\')'].concat(history));
22+
expect(i).to.deep.equal(history);
2323
});
2424
it('removes URI having Mongo from history for srv', () => {
2525
const i = ['m = new Mongo(\'mongodb+srv://admin:[email protected]/admin\')', 'db.shipwrecks.findOne()', 'use ships'];
2626
changeHistory(i);
27-
expect(i).to.deep.equal(['m = new Mongo(\'mongodb+srv://admin:[email protected]/admin\')'].concat(history));
27+
expect(i).to.deep.equal(history);
2828
});
2929

3030
it('leaves history as is if command is not sensitive', () => {
@@ -57,6 +57,12 @@ describe('changeHistory', () => {
5757
expect(i).to.deep.equal(history);
5858
});
5959

60+
it('removes sensitive raw commands from history', () => {
61+
const i = ['db.runCommand({createUser: "reportUser256", pwd: "pwd", roles: {] })', 'db.shipwrecks.findOne()', 'use ships'];
62+
changeHistory(i, true);
63+
expect(i).to.deep.equal(history);
64+
});
65+
6066
it('leaves history as is if command is not sensitive', () => {
6167
const i = ['db.shipwrecks.find({quasou: "depth unknown"})', 'db.shipwrecks.findOne()', 'use ships'];
6268
const cloned = Array.from(i);

packages/history/src/history.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
import redactInfo from 'mongodb-redact';
2-
import redactPwd from './redact-pwd';
2+
3+
export const HIDDEN_COMMANDS = 'createUser|auth|updateUser|changeUserPassword|connect|Mongo';
34

45
/**
5-
* Modifies command history array based on sensitive information.
6+
* Modifies the history based on sensitive information.
67
* If redact option is passed, also redacts sensitive info.
78
*
8-
* @param {array} History - Array of commands, where the first command is the
9-
* most recent.
10-
*
11-
* @param {boolean} Redact - Option to redact sensitive info.
9+
* @param {String} history - Command string.
10+
* @param {boolean} redact - Option to redact sensitive info.
1211
*/
1312
export function changeHistory(history: string[], redact = false): void {
14-
const hiddenCommands =
15-
RegExp('createUser|auth|updateUser|changeUserPassword|connect', 'g');
13+
const hiddenCommands = new RegExp(HIDDEN_COMMANDS, 'g');
1614

1715
if (hiddenCommands.test(history[0])) {
1816
history.shift();
19-
return;
20-
}
21-
if (/Mongo\(([^+)]+)\)/g.test(history[0])) {
22-
history[0] = history[0].replace(/Mongo\(([^+)]+)\)/g, (substr) => redactPwd(substr));
23-
return;
17+
} else {
18+
history[0] = removeCommand(history[0], redact);
2419
}
20+
}
2521

26-
if (redact) history[0] = redactInfo(history[0]);
22+
export function removeCommand(history: string, redact = false): string {
23+
if (redact) {
24+
return redactInfo(history);
25+
}
26+
return history;
2727
}
2828

packages/history/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export * from './history';
1+
import { changeHistory, removeCommand, HIDDEN_COMMANDS } from './history';
22
import retractPassword from './redact-pwd';
3-
export { retractPassword };
3+
export { retractPassword, changeHistory, removeCommand, HIDDEN_COMMANDS };

packages/java-shell/package-lock.json

Lines changed: 22 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/shell-api/package-lock.json

Lines changed: 12 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/shell-api/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"@mongosh/errors": "^0.1.0",
3838
"@mongosh/history": "^0.1.0",
3939
"@mongosh/i18n": "^0.1.0",
40-
"@mongosh/service-provider-core": "^0.1.0"
40+
"@mongosh/service-provider-core": "^0.1.0",
41+
"mongodb-redact": "^0.2.0"
4142
}
4243
}

packages/shell-api/src/collection.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
} from './index';
2525
import { MongoshInvalidInputError, MongoshRuntimeError } from '@mongosh/errors';
2626
import Bulk from './bulk';
27+
import { HIDDEN_COMMANDS } from '@mongosh/history';
2728

2829
@shellApiClassDefault
2930
@hasAsyncChild
@@ -1228,7 +1229,11 @@ export default class Collection extends ShellApiClass {
12281229
throw new MongoshInvalidInputError('The "commandName" argument cannot be passed as an option to "runCommand".');
12291230
}
12301231

1231-
this._emitCollectionApiCall('runCommand', { commandName });
1232+
1233+
const hiddenCommands = new RegExp(HIDDEN_COMMANDS);
1234+
if (!hiddenCommands.test(commandName)) {
1235+
this._emitCollectionApiCall('runCommand', { commandName });
1236+
}
12321237
return await this._mongo._serviceProvider.runCommand(
12331238
this._database._name,
12341239
{

packages/shell-api/src/database.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
} from '@mongosh/service-provider-core';
2525
import { AggregationCursor, CommandResult } from './index';
2626
import { MongoshInvalidInputError, MongoshRuntimeError, MongoshUnimplementedError } from '@mongosh/errors';
27+
import { HIDDEN_COMMANDS } from '@mongosh/history';
2728

2829
@shellApiClassDefault
2930
@hasAsyncChild
@@ -135,7 +136,10 @@ export default class Database extends ShellApiClass {
135136
@returnsPromise
136137
async runCommand(cmd: any): Promise<any> {
137138
assertArgsDefined(cmd);
138-
this._emitDatabaseApiCall('runCommand', { cmd });
139+
const hiddenCommands = new RegExp(HIDDEN_COMMANDS);
140+
if (!Object.keys(cmd).some(k => hiddenCommands.test(k))) {
141+
this._emitDatabaseApiCall('runCommand', { cmd });
142+
}
139143
return this._mongo._serviceProvider.runCommand(this._name, cmd);
140144
}
141145

@@ -150,7 +154,10 @@ export default class Database extends ShellApiClass {
150154
@serverVersions(['3.4.0', ServerVersions.latest])
151155
adminCommand(cmd: any): Promise<any> {
152156
assertArgsDefined(cmd);
153-
this._emitDatabaseApiCall( 'adminCommand', { cmd });
157+
const hiddenCommands = new RegExp(HIDDEN_COMMANDS);
158+
if (!Object.keys(cmd).some(k => hiddenCommands.test(k))) {
159+
this._emitDatabaseApiCall('adminCommand', { cmd });
160+
}
154161
return this._mongo._serviceProvider.runCommand(ADMIN_DB, cmd);
155162
}
156163

packages/shell-api/src/shell-internal-state.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { MongoshInvalidInputError } from '@mongosh/errors';
1717
import AsyncWriter from '@mongosh/async-rewriter';
1818
import { toIgnore } from './decorators';
1919
import NoDatabase from './no-db';
20+
import redactInfo from 'mongodb-redact';
2021

2122
/**
2223
* Anything to do with the internal shell state is stored here.
@@ -57,7 +58,10 @@ export default class ShellInternalState {
5758
async fetchConnectionInfo(): Promise<void> {
5859
if (!this.cliOptions.nodb) {
5960
this.connectionInfo = await this.currentDb._mongo._serviceProvider.getConnectionInfo();
60-
this.messageBus.emit('mongosh:connect', this.connectionInfo.extraInfo);
61+
this.messageBus.emit('mongosh:connect', {
62+
...this.connectionInfo.extraInfo,
63+
uri: redactInfo(this.connectionInfo.extraInfo.uri)
64+
});
6165
}
6266
}
6367

packages/shell-evaluator/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
},
2828
"dependencies": {
2929
"@mongosh/async-rewriter": "^0.1.0",
30+
"@mongosh/history": "^0.1.0",
3031
"@mongosh/service-provider-core": "^0.1.0",
3132
"@mongosh/shell-api": "^0.1.0"
3233
},

0 commit comments

Comments
 (0)