Mask sensitive information when logging (#1790)
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
var FileLoggerAdapter = require('../src/Adapters/Logger/FileLoggerAdapter').FileLoggerAdapter;
|
var FileLoggerAdapter = require('../src/Adapters/Logger/FileLoggerAdapter').FileLoggerAdapter;
|
||||||
var Parse = require('parse/node').Parse;
|
var Parse = require('parse/node').Parse;
|
||||||
|
var request = require('request');
|
||||||
|
|
||||||
describe('info logs', () => {
|
describe('info logs', () => {
|
||||||
|
|
||||||
@@ -45,3 +48,55 @@ describe('error logs', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('verbose logs', () => {
|
||||||
|
|
||||||
|
it("mask sensitive information in _User class", (done) => {
|
||||||
|
let customConfig = Object.assign({}, defaultConfiguration, {verbose: true});
|
||||||
|
setServerConfiguration(customConfig);
|
||||||
|
createTestUser().then(() => {
|
||||||
|
let fileLoggerAdapter = new FileLoggerAdapter();
|
||||||
|
return fileLoggerAdapter.query({
|
||||||
|
from: new Date(Date.now() - 500),
|
||||||
|
size: 100,
|
||||||
|
level: 'verbose'
|
||||||
|
});
|
||||||
|
}).then((results) => {
|
||||||
|
expect(results[1].message.includes('"password": "********"')).toEqual(true);
|
||||||
|
var headers = {
|
||||||
|
'X-Parse-Application-Id': 'test',
|
||||||
|
'X-Parse-REST-API-Key': 'rest'
|
||||||
|
};
|
||||||
|
request.get({
|
||||||
|
headers: headers,
|
||||||
|
url: 'http://localhost:8378/1/login?username=test&password=moon-y'
|
||||||
|
}, (error, response, body) => {
|
||||||
|
let fileLoggerAdapter = new FileLoggerAdapter();
|
||||||
|
return fileLoggerAdapter.query({
|
||||||
|
from: new Date(Date.now() - 500),
|
||||||
|
size: 100,
|
||||||
|
level: 'verbose'
|
||||||
|
}).then((results) => {
|
||||||
|
expect(results[1].message.includes('password=********')).toEqual(true);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not mask information in non _User class", (done) => {
|
||||||
|
let obj = new Parse.Object('users');
|
||||||
|
obj.set('password', 'pw');
|
||||||
|
obj.save().then(() => {
|
||||||
|
let fileLoggerAdapter = new FileLoggerAdapter();
|
||||||
|
return fileLoggerAdapter.query({
|
||||||
|
from: new Date(Date.now() - 500),
|
||||||
|
size: 100,
|
||||||
|
level: 'verbose'
|
||||||
|
});
|
||||||
|
}).then((results) => {
|
||||||
|
expect(results[1].message.includes('"password": "pw"')).toEqual(true);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
// components that external developers may be modifying.
|
// components that external developers may be modifying.
|
||||||
|
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
|
import url from 'url';
|
||||||
import log from './logger';
|
import log from './logger';
|
||||||
|
|
||||||
export default class PromiseRouter {
|
export default class PromiseRouter {
|
||||||
@@ -154,8 +155,8 @@ export default class PromiseRouter {
|
|||||||
function makeExpressHandler(promiseHandler) {
|
function makeExpressHandler(promiseHandler) {
|
||||||
return function(req, res, next) {
|
return function(req, res, next) {
|
||||||
try {
|
try {
|
||||||
log.verbose(req.method, req.originalUrl, req.headers,
|
log.verbose(req.method, maskSensitiveUrl(req), req.headers,
|
||||||
JSON.stringify(req.body, null, 2));
|
JSON.stringify(maskSensitiveBody(req), null, 2));
|
||||||
promiseHandler(req).then((result) => {
|
promiseHandler(req).then((result) => {
|
||||||
if (!result.response && !result.location && !result.text) {
|
if (!result.response && !result.location && !result.text) {
|
||||||
log.error('the handler did not include a "response" or a "location" field');
|
log.error('the handler did not include a "response" or a "location" field');
|
||||||
@@ -194,3 +195,34 @@ function makeExpressHandler(promiseHandler) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function maskSensitiveBody(req) {
|
||||||
|
let maskBody = Object.assign({}, req.body);
|
||||||
|
let shouldMaskBody = (req.method === 'POST' && req.originalUrl.endsWith('/users')
|
||||||
|
&& !req.originalUrl.includes('classes')) ||
|
||||||
|
(req.method === 'PUT' && /users\/\w+$/.test(req.originalUrl)
|
||||||
|
&& !req.originalUrl.includes('classes')) ||
|
||||||
|
(req.originalUrl.includes('classes/_User'));
|
||||||
|
if (shouldMaskBody) {
|
||||||
|
for (let key of Object.keys(maskBody)) {
|
||||||
|
if (key == 'password') {
|
||||||
|
maskBody[key] = '********';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maskBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
function maskSensitiveUrl(req) {
|
||||||
|
let maskUrl = req.originalUrl.toString();
|
||||||
|
let shouldMaskUrl = req.method === 'GET' && req.originalUrl.includes('/login')
|
||||||
|
&& !req.originalUrl.includes('classes');
|
||||||
|
if (shouldMaskUrl) {
|
||||||
|
let password = url.parse(req.originalUrl, true).query.password;
|
||||||
|
if (password) {
|
||||||
|
maskUrl = maskUrl.replace('password=' + password, 'password=********')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maskUrl;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user