Scrub Passwords with URL Encoded Characters (#4433)
* scrub passwords with url encoded characters from logs * compose query string from parsed params, redacting based on key if needed
This commit is contained in:
committed by
Florent Vilmart
parent
04f8673edd
commit
7a9d4044af
@@ -62,4 +62,93 @@ describe('LogsRouter', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const headers = {
|
||||||
|
'X-Parse-Application-Id': 'test',
|
||||||
|
'X-Parse-REST-API-Key': 'rest',
|
||||||
|
'X-Parse-Master-Key': 'test'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies simple passwords in GET login requests with special characters are scrubbed from the verbose log
|
||||||
|
*/
|
||||||
|
it('does scrub simple passwords on GET login', done => {
|
||||||
|
reconfigureServer({
|
||||||
|
verbose: true
|
||||||
|
}).then(function() {
|
||||||
|
request.get({
|
||||||
|
headers: headers,
|
||||||
|
url: 'http://localhost:8378/1/login?username=test&password=simplepass.com'
|
||||||
|
}, () => {
|
||||||
|
request.get({
|
||||||
|
url: 'http://localhost:8378/1/scriptlog?size=4&level=verbose',
|
||||||
|
json: true,
|
||||||
|
headers: headers
|
||||||
|
}, (error, response, body) => {
|
||||||
|
expect(response.statusCode).toEqual(200);
|
||||||
|
// 4th entry is our actual GET request
|
||||||
|
expect(body[3].url).toEqual('/1/login?username=test&password=********');
|
||||||
|
expect(body[3].message).toEqual('REQUEST for [GET] /1/login?username=test&password=********: {}');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies complex passwords in GET login requests with special characters are scrubbed from the verbose log
|
||||||
|
*/
|
||||||
|
it('does scrub complex passwords on GET login', done => {
|
||||||
|
reconfigureServer({
|
||||||
|
verbose: true
|
||||||
|
}).then(function() {
|
||||||
|
request.get({
|
||||||
|
headers: headers,
|
||||||
|
// using urlencoded password, 'simple @,/?:&=+$#pass.com'
|
||||||
|
url: 'http://localhost:8378/1/login?username=test&password=simple%20%40%2C%2F%3F%3A%26%3D%2B%24%23pass.com'
|
||||||
|
}, () => {
|
||||||
|
request.get({
|
||||||
|
url: 'http://localhost:8378/1/scriptlog?size=4&level=verbose',
|
||||||
|
json: true,
|
||||||
|
headers: headers
|
||||||
|
}, (error, response, body) => {
|
||||||
|
expect(response.statusCode).toEqual(200);
|
||||||
|
// 4th entry is our actual GET request
|
||||||
|
expect(body[3].url).toEqual('/1/login?username=test&password=********');
|
||||||
|
expect(body[3].message).toEqual('REQUEST for [GET] /1/login?username=test&password=********: {}');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies fields in POST login requests are NOT present in the verbose log
|
||||||
|
*/
|
||||||
|
it('does not have password field in POST login', done => {
|
||||||
|
reconfigureServer({
|
||||||
|
verbose: true
|
||||||
|
}).then(function() {
|
||||||
|
request.post({
|
||||||
|
headers: headers,
|
||||||
|
url: 'http://localhost:8378/1/login',
|
||||||
|
data: {
|
||||||
|
username: 'test',
|
||||||
|
password: 'simplepass.com'
|
||||||
|
}
|
||||||
|
}, () => {
|
||||||
|
request.get({
|
||||||
|
url: 'http://localhost:8378/1/scriptlog?size=4&level=verbose',
|
||||||
|
json: true,
|
||||||
|
headers: headers
|
||||||
|
}, (error, response, body) => {
|
||||||
|
expect(response.statusCode).toEqual(200);
|
||||||
|
// 4th entry is our actual GET request
|
||||||
|
expect(body[3].url).toEqual('/1/login');
|
||||||
|
expect(body[3].message).toEqual('REQUEST for [POST] /1/login: {}');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,12 +46,25 @@ export class LoggerController extends AdaptableController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maskSensitiveUrl(urlString) {
|
maskSensitiveUrl(urlString) {
|
||||||
const password = url.parse(urlString, true).query.password;
|
const urlObj = url.parse(urlString, true);
|
||||||
|
const query = urlObj.query;
|
||||||
|
let sanitizedQuery = '?';
|
||||||
|
|
||||||
if (password) {
|
for(const key in query) {
|
||||||
urlString = urlString.replace('password=' + password, 'password=********');
|
if(key !== 'password') {
|
||||||
|
// normal value
|
||||||
|
sanitizedQuery += key + '=' + query[key] + '&';
|
||||||
|
} else {
|
||||||
|
// password value, redact it
|
||||||
|
sanitizedQuery += key + '=' + '********' + '&';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return urlString;
|
|
||||||
|
// trim last character, ? or &
|
||||||
|
sanitizedQuery = sanitizedQuery.slice(0, -1);
|
||||||
|
|
||||||
|
// return original path name with sanitized params attached
|
||||||
|
return urlObj.pathname + sanitizedQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
maskSensitive(argArray) {
|
maskSensitive(argArray) {
|
||||||
|
|||||||
Reference in New Issue
Block a user