diff --git a/Documentation/Filters/Masking.md b/Documentation/Filters/Masking.md new file mode 100644 index 000000000..40b9aeae0 --- /dev/null +++ b/Documentation/Filters/Masking.md @@ -0,0 +1,243 @@ +# Masking + +## Overview +With the _masking_ filter it is possible to obfuscate the returned +value of a particular column. + +For instance, suppose there is a table _person_ that, among other +columns, contains the column _ssn_ where the social security number +of a person is stored. + +With the masking filter it is possible to specify that when the _ssn_ +field is queried, a masked value is returned unless the user making +the query is a specific one. That is, when making the query +``` +> SELECT name, ssn FROM person; +``` +instead of getting the real result, as in +``` ++-------+------------+ ++ name | ssn | ++-------+------------+ +| Alice | 721-07-4426 | +| Bob | 435-22-3267 | +... +``` +the _ssn_ would be masked, as in +``` ++-------+-------------+ ++ name | ssn | ++-------+-------------+ +| Alice | XXX-XX-XXXX | +| Bob | XXX-XX-XXXX | +... +``` + +Note that he masking filter alone is *not* sufficient for preventing +access to a particular column. As the masking filter works on the column +name alone a query like +``` +> SELECT name, concat(ssn) FROM person; +``` +will reveal the value. Also, executing a query like +``` +> SELECT name FROM person WHERE ssn = ...; +``` +a sufficient number of times with different _ssn_ values, will, eventually, +reveal the social security number of all persons in the database. + +For a secure solution, the masking filter *must* be combined with the +firewall filter to prevent the use of functions and the use of particular +columns in where-clauses. + +## Configuration + +The masking filter is taken into use with the following kind of +configuration setup. + +``` +[Mask-SSN] +type=filter +module=masking +rules_file=... + +[SomeService] +type=service +... +filters=Mask-SSN +``` + +# Filter Parameter + +The masking filter has one mandatory parameter - `rules_file`. + +#### `rules_file` + +Specifies the path of the file where the masking rules are stored. +A relative path is interpreted relative to the _data directory_ of +MariaDB MaxScale. + +``` +rules_file=/path/to/rules-file +``` + +# Rules + +The masking rules are expressed as a JSON object. + +The top-level object is expected to contain a key `rules` whose +value is an array of rule objects. +``` +{ + "rules": [ ... ] +} +``` + +## Rule + +Each rule in the rules array is a JSON object, expected to +contain the keys `replace`, `with`, `applies_to` and +`exempted`. The two former ones are obligatory and the two +latter ones optional. + +``` +{ + "rules": [ + { + "replace": { ... }, + "with": { ... }, + "applies_to": [ ... ], + "exempted": [ ... ] + } + ] +} +``` + +#### `replace` + +The value of this key is an object that specifies the column +whose values should be masked. The object must contain the key +`column` and may contain the keys `table` and `database`. The +value of these keys must be a string. + +If only `column` is specified, then a column with that name +matches irrespective of the table and database. If `table` +is specified, then the column matches only if it is in a table +with the specified name, and if `database` is specified when +the column matches only if it is in a database with the +specified name. + +``` +{ + "rules": [ + { + "replace": { + "database": "db1", + "table": "person", + "column": "ssn" + }, + "with": { ... }, + "applies_to": [ ... ], + "exempted": [ ... ] + } + ] +} +``` + +#### `with` + +The value of this key is an object that specifies what the value +of the matched column should be replaced with. Currently, the object +is expected to contain either the key `value` or the key `fill`. The +value of both must be a string. If both keys are specified, then +`value` takes presedence. + +If `value` is specified, then its value is used to replace the actual +value verbatim and the length of the specified value must match the +actual returned value (from the server) exactly. If the lengths do +not match, then if `fill` is specified its value will be used to +mask the actual value. Otherwise an error is logged and the value +is *not* masked. + +If `fill` is specified, then its value will be used for masking the +value; as such if the lenghts match, by cutting it if the actual value +is shorter, and by repeating it, fully or partially, the necessary +amount of times, if the actual value is longer. +``` +{ + "rules": [ + { + "replace": { + "column": "ssn" + }, + "with": { + "value": "XXX-XX-XXXX" + }, + "applies_to": [ ... ], + "exempted": [ ... ] + }, + { + "replace": { + "column": "age" + }, + "with": { + "fill": "*" + }, + "applies_to": [ ... ], + "exempted": [ ... ] + }, + { + "replace": { + "column": "creditcard" + }, + "with": { + "value": "1234123412341234" + "fill": "0" + }, + "applies_to": [ ... ], + "exempted": [ ... ] + }, + ] +} +``` + +#### `applies_to` + +With this _optional_ key, whose value must be an array of strings, +it can be specified what users the rule is applied to. Each string +should be a MariaDB account string, that is, `%` is a wildcard. + +``` +{ + "rules": [ + { + "replace": { ... }, + "with": { ... }, + "applies_to": [ "'alice'@'host'", "'bob'@'%'" ], + "exempted": [ ... ] + } + ] +} +``` + +If this key is not specified, then the masking is performed for all +users, except the ones exempted using the key `exempted`. + +#### `exempted` + +With this _optional_ key, whose value must be an array of strings, +it can be specified what users the rule is *not* applied to. Each +string should be a MariaDB account string, that is, `%` is a wildcard. + +``` +{ + "rules": [ + { + "replace": { ... }, + "with": { ... }, + "applies_to": [ ... ], + "exempted": [ "'admin'" ] + } + ] +} +```