Last active
August 31, 2024 02:48
-
-
Save iOnline247/45ea7b2ff328ca797d6fab9f8cbed843 to your computer and use it in GitHub Desktop.
Data masking perf for objects that are logged.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const WARMUP_LOOPS = 100000; | |
//#region Utils | |
function escapeRegExp(string) { | |
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string | |
} | |
function createUserObj() { | |
return { | |
id: 123, | |
email: "user@example.com", | |
password: "secret", | |
here: { | |
email: "nope-topLevel", | |
ssn: "123-45-6789", | |
}, | |
nestedObj: { | |
here: { | |
email: "nope-nested", | |
ssn: "123-45-6789", | |
}, | |
}, | |
arrOfObjs: [ | |
{ | |
email: "nope1", | |
ssn: "111-11-1111", | |
}, | |
{ | |
email: "nope2", | |
ssn: "222-22-2222", | |
}, | |
], | |
}; | |
} | |
const sanitizedFields = ["email", "password", "ssn"]; | |
function dataMasker(mask = "*".repeat(8), sensitiveFields = sanitizedFields) { | |
return function createProxyObject(obj) { | |
return new Proxy(obj, { | |
get(target, prop) { | |
if (sensitiveFields.includes(prop)) { | |
return mask; | |
} | |
const value = target[prop]; | |
if (value && typeof value === "object") { | |
return createProxyObject(value); | |
} | |
return value; | |
}, | |
}); | |
}; | |
} | |
class User { | |
address; | |
id; | |
password; | |
ssn; | |
constructor(id, address, password, ssn) { | |
this.address = address; | |
this.id = id; | |
this.password = password; | |
this.ssn = ssn; | |
} | |
} | |
//#endregion Utils | |
const maskSensitiveObject = dataMasker(); | |
function proxyObjMasking(shouldLog = false) { | |
const user = maskSensitiveObject(createUserObj()); | |
user.id **= 2; | |
const resultObj = JSON.stringify(user); | |
if (shouldLog) { | |
console.log("proxyObjMasking\n"); | |
console.log(resultObj); | |
console.log(""); | |
} | |
} | |
function knownObjMasking(shouldLog) { | |
const user = createUserObj(); | |
user.id **= 2; | |
user.email = "*".repeat(8); | |
user.password = "*".repeat(8); | |
user.here.email = "*".repeat(8); | |
user.here.ssn = "*".repeat(8); | |
user.nestedObj.here.email = "*".repeat(8); | |
user.nestedObj.here.ssn = "*".repeat(8); | |
user.arrOfObjs[0].email = "*".repeat(8); | |
user.arrOfObjs[0].ssn = "*".repeat(8); | |
user.arrOfObjs[1].email = "*".repeat(8); | |
user.arrOfObjs[1].ssn = "*".repeat(8); | |
const resultObj = JSON.stringify(user); | |
if (shouldLog) { | |
console.log("knownObjMasking\n"); | |
console.log(resultObj); | |
} | |
} | |
function regexObjMasking(shouldLog) { | |
const user = createUserObj(); | |
user.id **= 2; | |
let resultJson = JSON.stringify(user); | |
for (const field of sanitizedFields) { | |
resultJson = resultJson.replace( | |
new RegExp(`"(${escapeRegExp(field)})":"[^"]+"`, "g"), | |
`$1:"${"*".repeat(8)}"`, | |
); | |
} | |
if (shouldLog) { | |
console.log("regexObjMasking\n"); | |
console.log(resultJson); | |
} | |
} | |
function classObjMasking(shouldLog) { | |
const user = maskSensitiveObject( | |
new User(123, "sensitive-but-not-masked", "password", "123-45-6789"), | |
); | |
user.id **= 2; | |
const resultJson = JSON.stringify(user); | |
if (shouldLog) { | |
console.log("classObjMasking\n"); | |
console.log(resultJson); | |
} | |
} | |
for (let i = 0; i < WARMUP_LOOPS; i++) { | |
proxyObjMasking(); | |
knownObjMasking(); | |
regexObjMasking(); | |
classObjMasking(); | |
} | |
//#region Start Tests | |
//#region ProxyObjMasking | |
console.log(`\n${"*".repeat(25)}`); | |
const startProxyObjMasking = process.hrtime(); | |
proxyObjMasking(true); | |
const endProxyObjMasking = process.hrtime(startProxyObjMasking); | |
console.log( | |
`\n\nExecution time: ${endProxyObjMasking[0]} seconds and ${endProxyObjMasking[1] / 1e6} milliseconds`, | |
); | |
console.log(`\n${"*".repeat(25)}\n`); | |
//#endregion ProxyObjMasking | |
//#region Regex Parsing | |
console.log(`\n${"*".repeat(25)}`); | |
const startRegexObjMasking = process.hrtime(); | |
regexObjMasking(true); | |
const endRegexObjMasking = process.hrtime(startRegexObjMasking); | |
console.log( | |
`\n\nExecution time: ${endRegexObjMasking[0]} seconds and ${endRegexObjMasking[1] / 1e6} milliseconds`, | |
); | |
console.log(`\n${"*".repeat(25)}\n`); | |
//#endregion Regex Parsing | |
//#region JSON Parsing | |
console.log(`\n${"*".repeat(25)}`); | |
const startKnownObjMasking = process.hrtime(); | |
knownObjMasking(true); | |
const endKnownObjMasking = process.hrtime(startKnownObjMasking); | |
console.log( | |
`\n\nExecution time: ${endKnownObjMasking[0]} seconds and ${endKnownObjMasking[1] / 1e6} milliseconds`, | |
); | |
console.log(`\n${"*".repeat(25)}\n`); | |
//#endregion JSON Parsing | |
//#region ClassObjMasking | |
console.log(`\n${"*".repeat(25)}`); | |
const startClassObjMasking = process.hrtime(); | |
classObjMasking(true); | |
const endClassObjMasking = process.hrtime(startClassObjMasking); | |
console.log( | |
`\n\nExecution time: ${endClassObjMasking[0]} seconds and ${endClassObjMasking[1] / 1e6} milliseconds`, | |
); | |
console.log(`\n${"*".repeat(25)}\n`); | |
//#endregion ClassObjMasking | |
//#endregion Start Tests | |
//#region Overwritten Proxy Property | |
console.log(`${"*".repeat(25)}\n`); | |
const user = maskSensitiveObject(createUserObj()); | |
user.here = { email: "nope", nestedObj: {} }; | |
user.here.nestedObj.email = "nope"; | |
user.here.nestedObj.password = "password"; | |
user.arrOfObjs.push({ | |
email: "nope", | |
password: "remove-me", | |
nestedObj: { ssn: "do-not-log" }, | |
}); | |
console.log(`Overwritten Proxy Property\n\n${JSON.stringify(user)}`); | |
console.log(`\n${"*".repeat(25)}\n`); | |
console.log(`${"*".repeat(25)}\n`); | |
const emptyObj = maskSensitiveObject(Object.create(null)); | |
emptyObj.email = "nope"; | |
emptyObj.password = ""; | |
emptyObj.here = { email: "nope", nestedObj: {} }; | |
emptyObj.arrOfObjs = [{ nestedObj: { password: "nope", ssn: "remove" } }]; | |
emptyObj.arrOfObjs.push({ | |
email: "nope", | |
password: "", | |
nestedObj: { ssn: "do-not-log" }, | |
}); | |
console.log(`No Prototype Object\n\n${JSON.stringify(emptyObj)}`); | |
console.log(`\n${"*".repeat(25)}\n`); | |
//#endregion Overwritten Proxy Property | |
//#region Obtain sensitive values from object | |
const rawValues = Object.getOwnPropertyDescriptors(emptyObj); | |
console.log(JSON.stringify(rawValues)); | |
//#endregion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment