Strip personally identifiable information from user table for unauthorized users.
- add a config option to explicitly enumerate pii fields beyond email - in query controller, strip pii of user table results before sending out the door.
This commit is contained in:
committed by
Florent Vilmart
parent
a270632570
commit
01b05b060f
@@ -34,6 +34,7 @@ export class Config {
|
||||
this.fileKey = cacheInfo.fileKey;
|
||||
this.facebookAppIds = cacheInfo.facebookAppIds;
|
||||
this.allowClientClassCreation = cacheInfo.allowClientClassCreation;
|
||||
this.userSensitiveFields = cacheInfo.userSensitiveFields;
|
||||
|
||||
// Create a new DatabaseController per request
|
||||
if (cacheInfo.databaseController) {
|
||||
|
||||
@@ -113,6 +113,7 @@ class ParseServer {
|
||||
webhookKey,
|
||||
fileKey,
|
||||
facebookAppIds = [],
|
||||
userSensitiveFields = [],
|
||||
enableAnonymousUsers = defaults.enableAnonymousUsers,
|
||||
allowClientClassCreation = defaults.allowClientClassCreation,
|
||||
oauth = {},
|
||||
@@ -155,6 +156,11 @@ class ParseServer {
|
||||
throw 'When using an explicit database adapter, you must also use an explicit filesAdapter.';
|
||||
}
|
||||
|
||||
userSensitiveFields = Array.from(new Set(userSensitiveFields.concat(
|
||||
defaults.userSensitiveFields,
|
||||
userSensitiveFields
|
||||
)));
|
||||
|
||||
const loggerControllerAdapter = loadAdapter(loggerAdapter, WinstonLoggerAdapter, { jsonLogs, logsFolder, verbose, logLevel, silent });
|
||||
const loggerController = new LoggerController(loggerControllerAdapter, appId);
|
||||
logging.setLogger(loggerController);
|
||||
@@ -222,7 +228,8 @@ class ParseServer {
|
||||
revokeSessionOnPasswordReset,
|
||||
databaseController,
|
||||
schemaCacheTTL,
|
||||
enableSingleSchemaCache
|
||||
enableSingleSchemaCache,
|
||||
userSensitiveFields
|
||||
});
|
||||
|
||||
// To maintain compatibility. TODO: Remove in some version that breaks backwards compatibility
|
||||
|
||||
@@ -386,6 +386,32 @@ RestQuery.prototype.replaceDontSelect = function() {
|
||||
})
|
||||
};
|
||||
|
||||
const cleanResultOfSensitiveUserInfo = function (result, auth, config) {
|
||||
delete result.password;
|
||||
|
||||
if (auth.isMaster || (auth.user && auth.user.id === result.objectId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const field of config.userSensitiveFields) {
|
||||
delete result[field];
|
||||
}
|
||||
};
|
||||
|
||||
const cleanResultAuthData = function (result) {
|
||||
if (result.authData) {
|
||||
Object.keys(result.authData).forEach((provider) => {
|
||||
if (result.authData[provider] === null) {
|
||||
delete result.authData[provider];
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(result.authData).length == 0) {
|
||||
delete result.authData;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Returns a promise for whether it was successful.
|
||||
// Populates this.response with an object that only has 'results'.
|
||||
RestQuery.prototype.runFind = function(options = {}) {
|
||||
@@ -406,18 +432,8 @@ RestQuery.prototype.runFind = function(options = {}) {
|
||||
this.className, this.restWhere, findOptions).then((results) => {
|
||||
if (this.className === '_User') {
|
||||
for (var result of results) {
|
||||
delete result.password;
|
||||
|
||||
if (result.authData) {
|
||||
Object.keys(result.authData).forEach((provider) => {
|
||||
if (result.authData[provider] === null) {
|
||||
delete result.authData[provider];
|
||||
}
|
||||
});
|
||||
if (Object.keys(result.authData).length == 0) {
|
||||
delete result.authData;
|
||||
}
|
||||
}
|
||||
cleanResultOfSensitiveUserInfo(result, this.auth, this.config);
|
||||
cleanResultAuthData(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -160,6 +160,10 @@ export default {
|
||||
help: "Max file size for uploads.",
|
||||
default: "20mb"
|
||||
},
|
||||
"userSensitiveFields": {
|
||||
help: "Personally identifiable information fields in the user table the should be removed for non-authorized users.",
|
||||
default: "email"
|
||||
},
|
||||
"sessionLength": {
|
||||
env: "PARSE_SERVER_SESSION_LENGTH",
|
||||
help: "Session duration, defaults to 1 year",
|
||||
|
||||
@@ -31,5 +31,6 @@ export default {
|
||||
sessionLength: 31536000,
|
||||
expireInactiveSessions: true,
|
||||
revokeSessionOnPasswordReset: true,
|
||||
schemaCacheTTL: 5000 // in ms
|
||||
schemaCacheTTL: 5000, // in ms
|
||||
userSensitiveFields: ['email']
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user