Configuring Sanitizer Functions

Quick Intro

Before jumping into individual sanitization methods, here is some quick conventional code to jump in to.

Sanitizer Functions
const sanitizers = {
replaceText: [funcs, funcs], // Function Signature: (str, element, isCensored)
replaceValue: [funcs, funcs], // Function Signature: (str, element, isCensored)
censorElement: [funcs, funcs], // Function Signature: (element)
censorStorageVal: [funcs, funcs], // Function Signature: ([key, val])
url: [funcs, funcs], // Function Signature: (urlStr)
network: [funcs, funcs], // Function Signature: ({reqObj, resObj})
reduxState: [funcs, funcs], // Function Signature: (stateObj)
reduxAction: [funcs, funcs], // Function Signature: (actionObj)
};
wisdom('init', __PROJECT_ID_HERE__, {
sanitizers,
});

Full Example

Jump in with some code before we explain each method individually.

Example Sanitizers
import _ from 'lodash'; // example dependency
const sanitizers = {
replaceText: [
(str, el, isCensored) => {
// Replace all numbers within body.
return document.body.contains(el)
? str.replace(/[0-9]/g, '*')
: str;
}
],
replaceValue: [
(str, el, isCensored) => {
// Remove all letters from form field values.
return str.replace(/[a-zA-Z]/g, '*');
}
],
censorElement: [
// Censor all header tags.
el => el.tagName.startsWith('h'),
],
censorStorageVal: [
([key, val]) => {
// Censor matching cookies, localstorage, sessionStorage
return key.startsWith('_') || key==='authJWT';
},
],
url: [
(url) => {
// Delete "secret" and "authtoken" parameters.
try {
const u = new URL(url);
u.searchParams.delete('secret');
u.searchParams.delete('authtoken');
return u+'#__';
}
catch (e) {
return url;
}
}
],
network: [
({req, res}) => {
// You may delete values, though for debugging,
// often overwrite paints a more complete picture.
let censoredReq = _.cloneDeep(req);
_.set(censoredReq, 'headers.password', '__CENSORED__');
_.set(censoredReq, 'headers.x-auth', '__CENSORED__');
return {req: censoredReq, res,}
}
],
reduxState: [
(state) => {
// Ommit certain properties from
// Redux State, like passwords.
return _.omit(state, ['user.password']);
},
],
reduxAction: [
(action) => {
// Ommit certain action properties from Redux, like passwords.
// Remember to return a clone of the action.
if (action.type === 'SET_USER_FULFILLED') {
let actionClone = _.cloneDeep(action);
_.set(actionClone, 'account.user.password', '__CENSORED__');
_.set(actionClone, 'example.nested.deeply', '__CENSORED__');
return actionClone;
}
return action;
}
],
};
wisdom('init', __PROJECT_ID_HERE__, {
sanitizers,
});

Sanitizer Hooks Reference

Sanitize Page Text

replaceText method hook:

  • str The element's text.
  • el The element reference
  • isCensored Whether the element is considered
  • return: new string

Imagine for a moment you have a banking app. Here is how you can change all numbers of the webpage text (not form inputs) to bullet points.

Example Sanitizers
wisdom('init', __PROJECT_ID_HERE__, {
sanitizers: {
replaceText: [
(str, el, isCensored) => {
// Replace all numbers within body.
return document.body.contains(el)
? str.replace(/[0-9]/g, '*')
: str;
}
],
}
});

Sanitize Form Values

Example Sanitizers
wisdom('init', __PROJECT_ID_HERE__, {
sanitizers: {
replaceValue: [
(str, el, isCensored) => {
// Remove all letters from form field values.
return str.replace(/[a-zA-Z]/g, '*');
}
],
}
});

Censor Element

Which elements to sanitize- triggers various scrubbers- like element.value and text.

Example Sanitizers
wisdom('init', __PROJECT_ID_HERE__, {
sanitizers: {
censorElement: [
// Censor all header tags.
el => el.tagName.startsWith('h'),
],
}
});

Sanitize Browser Storage

Local Storage, Session Storage, Cookies.

Example Sanitizers
wisdom('init', __PROJECT_ID_HERE__, {
sanitizers: {
censorStorageVal: [
([key, val]) => {
// Censor matching cookies, localstorage, sessionStorage
return key.startsWith('_') || key==='authJWT';
},
],
}
});

Sanitize URLs

Example Sanitizers
wisdom('init', __PROJECT_ID_HERE__, {
sanitizers: {
url: [
(url) => {
// Delete "secret" and "authtoken" parameters.
try {
const u = new URL(url);
u.searchParams.delete('secret');
u.searchParams.delete('authtoken');
return u+'#__';
}
catch (e) {
return url;
}
}
],
}
});

Sanitize Network Request + Response

Example Sanitizers
import _ from 'lodash'; // example dependency
wisdom('init', __PROJECT_ID_HERE__, {
sanitizers: {
network: [
({req, res}) => {
// You may delete values, though for debugging,
// often overwrite paints a more complete picture.
let censoredReq = _.cloneDeep(req);
_.set(censoredReq, 'headers.password', '__CENSORED__');
_.set(censoredReq, 'headers.x-auth', '__CENSORED__');
return {req: censoredReq, res,}
}
],
}
});

Sanitize Redux State

Example Sanitizers
import _ from 'lodash'; // example dependency
wisdom('init', __PROJECT_ID_HERE__, {
sanitizers: {
reduxState: [
(state) => {
// Ommit certain properties from
// Redux State, like passwords.
return _.omit(state, ['user.password']);
},
],
}
});

Sanitize Redux Actions

Example Sanitizers
import _ from 'lodash'; // example dependency
wisdom('init', __PROJECT_ID_HERE__, {
sanitizers: {
reduxAction: [
(action) => {
// Ommit certain action properties from Redux, like passwords.
// Remember to return a clone of the action.
if (action.type === 'SET_USER_FULFILLED') {
let actionClone = _.cloneDeep(action);
_.set(actionClone, 'account.user.password', '__CENSORED__');
_.set(actionClone, 'example.nested.deeply', '__CENSORED__');
return actionClone;
}
return action;
}
],
}
});
Last updated on by John Gracey